前言
最近项目中遇得到了很多跟图片相关的技术点,这里主要是汇总一下,以备后期参考
1、前端二维码的生成与下载(兼容ie)
二维码生成
这里用了一个现有插件vue-qr
下载该插件
npm i vue-qr复制代码
在项目中引入该插件
import VueQr from 'vue-qr'复制代码
使用vue-qr
<el-dialog:area="[520, 400]"top="middle"no-scrollbartitle="小区二维码":visible.sync="qrCodeDia"><el-alertstyle="width: 105%;margin-left: -12px;margin-top: -12px;"title="请张贴此二维码于小区/单位内,居民扫描此二维码可录入人员信息。"type="info"simpleshow-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.idthis.config.value = httpthis.qrCodeDia = true},// 判断浏览器类型myBrowser() {var userAgent = navigator.userAgent // 取得浏览器的userAgent字符串var isOpera = userAgent.indexOf('Opera') > -1if (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.lengthvar 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.srcif (this.myBrowser() === 'IE' || this.myBrowser() === 'Edge') {// IE (浏览器)this.SaveAs5(url)} else {//! IE (非IE)var a = document.createElement('a') // 创建一个a节点插入的documentvar event = new MouseEvent('click') // 模拟鼠标click点击事件a.download = '小区二维码' // 设置a节点的download属性值a.href = url // 将图片的src赋值给a节点的hrefa.dispatchEvent(event)}},复制代码
2、h5端手机照片上传与拍照相关知识
上传与拍照方法
<template><div ref="imageUploadContainer" class="imageUploadContainer"><divv-for="(item, index) in filePreviewList":key="index"class="uploadPreviewItem previewItem"><imgclass="prevImg":style="{ width: '95px', height: '133px' }":src="item"@click="imgPreview(index)"/><i class="van-icon van-icon-clear deleteImgIcon" @click="deleteImg(index)"></i></div><divv-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 / 1024if (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 / 1024if (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 = thisconst ready = new FileReader() /* 开始读取指定File对象中的内容. 读取操作完成时,返回一个URL格式的字符串. */ready.readAsDataURL(file)ready.onload = function() {const re = this.resultthat.canvasDataURL(re, obj, callback) // 开始压缩}},复制代码
/* 利用canvas数据化图片进行压缩 *//* 图片转base64 */canvasDataURL(path, obj, callback) {const img = new Image()img.src = pathimg.onload = function() {const that = this // 指到img // 默认按比例压缩let w = that.widthlet h = that.heightconst scale = w / hw = obj.width || wh = obj.height || w / scaleconst quality = obj.quality // 默认图片质量为0.7 // 生成canvasconst canvas = document.createElement('canvas')const ctx = canvas.getContext('2d') // 创建属性节点const anw = document.createAttribute('width')anw.nodeValue = wconst anh = document.createAttribute('height')anh.nodeValue = hcanvas.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的头,并转化为byteconst bstr = atob(arr[1]) // 处理异常,将ascii码小于0的转换为大于0let n = bstr.lengthconst 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' // 转filereturn 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})}},
