前言
最近项目中遇得到了很多跟图片相关的技术点,这里主要是汇总一下,以备后期参考
1、前端二维码的生成与下载(兼容ie)
二维码生成
这里用了一个现有插件vue-qr
下载该插件
npm i vue-qr
复制代码
在项目中引入该插件
import VueQr from 'vue-qr'
复制代码
使用vue-qr
<el-dialog
:area="[520, 400]"
top="middle"
no-scrollbar
title="小区二维码"
:visible.sync="qrCodeDia"
>
<el-alert
style="width: 105%;margin-left: -12px;margin-top: -12px;"
title="请张贴此二维码于小区/单位内,居民扫描此二维码可录入人员信息。"
type="info"
simple
show-icon
:closable="false"
></el-alert>
<div v-if="qrCodeDia" id="qrcode" style="text-align: center;margin-top: 24px;">
<vue-qr :text="config.value" :size="200" :margin="0"></vue-qr>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="downloadImg()">
下载
</el-button>
</div>
</el-dialog>
复制代码
对应生成二维码与下载方法
/**
* @desc 展开二维码弹框
*/
async handleShowQr(item) {
const { data } = await httpAdress.getServerInfo()
const http =
data.scheme + '://' + data.ip + ':' + data.port + '/ossrs/app#/AddPerson/' + item.id
this.config.value = http
this.qrCodeDia = true
},
// 判断浏览器类型
myBrowser() {
var userAgent = navigator.userAgent // 取得浏览器的userAgent字符串
var isOpera = userAgent.indexOf('Opera') > -1
if (isOpera) {
return 'Opera'
}
if (userAgent.indexOf('Firefox') > -1) {
return 'FF'
}
if (userAgent.indexOf('Chrome') > -1) {
return 'Chrome'
}
if (userAgent.indexOf('Safari') > -1) {
return 'Safari'
}
if (userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1 && !isOpera) {
return 'IE'
}
if (userAgent.indexOf('Trident') > -1) {
return 'Edge'
}
},
// ②IE浏览器图片保存
SaveAs5(imgURL) {
var bstr = atob(imgURL.split(',')[1])
var n = bstr.length
var u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
var blob = new Blob([u8arr])
window.navigator.msSaveOrOpenBlob(blob, '小区二维码.jpg')
},
/**
* @author liujie22
* @desc 下载二维码
*/
downloadImg() {
var oQrcode = document.querySelector('#qrcode img')
var url = oQrcode.src
if (this.myBrowser() === 'IE' || this.myBrowser() === 'Edge') {
// IE (浏览器)
this.SaveAs5(url)
} else {
//! IE (非IE)
var a = document.createElement('a') // 创建一个a节点插入的document
var event = new MouseEvent('click') // 模拟鼠标click点击事件
a.download = '小区二维码' // 设置a节点的download属性值
a.href = url // 将图片的src赋值给a节点的href
a.dispatchEvent(event)
}
},
复制代码
2、h5端手机照片上传与拍照相关知识
上传与拍照方法
<template>
<div ref="imageUploadContainer" class="imageUploadContainer">
<div
v-for="(item, index) in filePreviewList"
:key="index"
class="uploadPreviewItem previewItem"
>
<img
class="prevImg"
:style="{ width: '95px', height: '133px' }"
:src="item"
@click="imgPreview(index)"
/>
<i class="van-icon van-icon-clear deleteImgIcon" @click="deleteImg(index)"></i>
</div>
<div
v-if="max === -1 || fileList.length < max"
ref="uploadBtn"
class="uploadBtn previewItem"
@click="onAddFileBtnClick"
>
<i class="van-icon van-icon-plus uploadeIcon"></i>
<input type="file" accept="image/jpg" @change="fileChange" />
</div>
</div>
</template>
复制代码
图片上传及压缩方法
// 文件选择变化事件
// 文件名不带后缀的文件上传会失败TODO:
async fileChange(e) {
// 数量检查
if (this.max && this.fileList.length >= 6) {
Toast('超过数量限制')
return false
}
let file = e.target.files[0]
// 取消选择的话file对象不存在
if (!file) {
return false
}
const that = this
// 图片大小检查
const ms = file.size / 1024
if (this.size && ms > this.size) {
that.photoCompress(
file,
{
width: 400,
height: 600,
// 调用压缩图片方法
quality: 0.9
},
async function(base64Codes) {
let bl = that.base64UrlToBlob(base64Codes)
// 图片大小检查
const mss = bl.size / 1024
if (that.size && mss > that.size) {
Toast(`超过${that.size}KB的大小限制`)
} else if (mss < 10) {
Toast(`不能小于10KB的大小限制`)
} else {
if (that.base64) {
bl = await that.toDataURL(bl)
}
that.trigger(bl)
}
}
)
} else if (ms < 10) {
Toast(`不能小于10KB的大小限制`)
} else {
if (this.base64) {
file = await this.toDataURL(file)
}
this.trigger(file)
}
},
复制代码
/*
*压缩图片
*file:文件(类型是图片格式),
*obj:文件压缩后对象width, height, quality(0-1)
*callback:容器或者回调函数
*/
photoCompress(file, obj, callback) {
const that = this
const ready = new FileReader() /* 开始读取指定File对象中的内容. 读取操作完成时,返回一个URL格式的字符串. */
ready.readAsDataURL(file)
ready.onload = function() {
const re = this.result
that.canvasDataURL(re, obj, callback) // 开始压缩
}
},
复制代码
/* 利用canvas数据化图片进行压缩 */
/* 图片转base64 */
canvasDataURL(path, obj, callback) {
const img = new Image()
img.src = path
img.onload = function() {
const that = this // 指到img // 默认按比例压缩
let w = that.width
let h = that.height
const scale = w / h
w = obj.width || w
h = obj.height || w / scale
const quality = obj.quality // 默认图片质量为0.7 // 生成canvas
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d') // 创建属性节点
const anw = document.createAttribute('width')
anw.nodeValue = w
const anh = document.createAttribute('height')
anh.nodeValue = h
canvas.setAttributeNode(anw)
canvas.setAttributeNode(anh)
ctx.drawImage(that, 0, 0, w, h) // 图像质量
// quality值越小,所绘制出的图像越模糊
const base64 = canvas.toDataURL('image/jpeg', quality) // 回调函数返回base64的值
callback(base64)
}
},
复制代码
/**
* base64 转 Blob 格式 和file格式
*/
base64UrlToBlob(urlData) {
const arr = urlData.split(',')
const mime = arr[0].match(/:(.*?);/)[1] // 去掉url的头,并转化为byte
const bstr = atob(arr[1]) // 处理异常,将ascii码小于0的转换为大于0
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
} // 转blob // return new Blob([u8arr], {type: mime})
const filename = Date.parse(new Date()) + '.jpg' // 转file
return new File([u8arr], filename, { type: mime })
},
复制代码
/**
* @Desc: 二进制数据转base65
*/
toDataURL(blob) {
return new Promise((resolve, reject) => {
const a = new FileReader()
a.onload = e => {
resolve(e.target.result)
}
a.readAsDataURL(blob)
})
},
复制代码
/**
* @Desc: 触发事件,调用父组件方法
*/
trigger(tar) {
this.fileList.concat([tar])
if (typeof tar === 'string') {
this.$emit('afterRead', { base: tar })
} else {
this.$emit('afterRead', { base: tar })
}
},
复制代码
图片展示
computed: {
// 预览列表
filePreviewList() {
return this.fileList.map(item => {
return typeof item === 'object' ? window.URL.createObjectURL(item) : item
})
}
},