1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 移动端图片上传并生成图片(图片上传/图片压缩/图片绘制/Vue纯前端)

移动端图片上传并生成图片(图片上传/图片压缩/图片绘制/Vue纯前端)

时间:2023-06-16 05:54:41

相关推荐

移动端图片上传并生成图片(图片上传/图片压缩/图片绘制/Vue纯前端)

如今用户上传图片,生成图保存分享这些都是h5页面的基操了吧,十分常见,实际操作起来也是满满的技能点,其实也有很多兼容问题的坑。

下面是以vue+elementUI做的一套,有需要的直接拿去~

如果有对原理感兴趣的,可看俺其他blog也有记录~

1、图片上传组件的使用

<el-upload:on-change="handleSuccess":multiple="false"class="picBox"action="#"list-type="picture-card":auto-upload="false"accept="image/*"style="height:50px"><div slot="file" slot-scope="{ file }" class="picBoxNew"><img class="el-thumbnail" :src="file.url" alt /></div></el-upload>mounted() {// 简单设置一下不要它的界面let oItemUp = document.getElementsByClassName("el-upload")[0];oItemUp.style.height = "52px";oItemUp.style.border = "none";oItemUp.style.background = "transparent";let oItemList = document.getElementsByClassName("el-upload-list")[0];oItemList.style.display = "none";}

2、从上传成功的方法里取file并压缩

图片压缩十分重要!市场上各式各样的手机型号意味着各式质量大小的图片要上传,我的测试拿着相机拍的图片往上传…永远不要相信你的用户,所以在上传之后一定要做一次压缩!!!(生成图片的时候还要做一次压缩!!!继续往下看吧)

handleSuccess(file) {const _that = this;console.log(file, "看这里🌹");compress(file.raw, function(val) {console.log(val, "sga🌹");const fr = new FileReader();fr.readAsDataURL(val);fr.onload = function() {// 显示图片console.log(this.width, this.height, "oko🌹");_that.usedUrl = this.result;// 上传成功--->//⚠️⚠️⚠️我这上传之后的图片要根据手机屏幕宽高对图片进行裁剪做处理,不需要的可以不看这个方法,直接跳最后一步生成图片!// 调方法设置对应宽高_that.checkImgWidth(_that.usedUrl);};});},//🐷图片压缩封装--我的位置在utils里,如果直接在页面用的话,别忘了this指向/** 图片压缩,默认同比例压缩* @param {Object} fileObj* 图片对象* 回调函数有一个参数,base64的字符串数据*/export function compress(fileObj, callback) {try {const image = new Image()image.src = URL.createObjectURL(fileObj)image.onload = function() {const that = this// 默认按比例压缩let w = that.widthlet h = that.heightconst scale = w / hw = fileObj.width || wh = fileObj.height || (w / scale)let quality = 0.7 // 默认图片质量为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)// 图像质量if (fileObj.quality && fileObj.quality <= 1 && fileObj.quality > 0) {quality = fileObj.quality}// quality值越小,所绘制出的图像越模糊const data = canvas.toDataURL('image/jpeg', quality)// 压缩完成执行回调const newFile = convertBase64UrlToBlob(data)callback(newFile)}} catch (e) {alert('压缩失败!')}}function convertBase64UrlToBlob(urlData) {const bytes = window.atob(urlData.split(',')[1]) // 去掉url的头,并转换为byte// 处理异常,将ascii码小于0的转换为大于0const ab = new ArrayBuffer(bytes.length)const ia = new Uint8Array(ab)for (let i = 0; i < bytes.length; i++) {ia[i] = bytes.charCodeAt(i)}return new Blob([ab], {type: 'image/png' })}

3、获取已上传图片宽高,根据手机屏幕宽高对图片进行裁剪

这一步,有人可能会跳过,但我建议看官过一遍,毕竟对于有些上传极扁、极长等不常规的图片时,不可避免的需要截取的,万物皆相通~

//看标题,我们需要对图片宽高、容器宽高(这里是手机屏幕宽高)动手脚//第二步调用的 _that.checkImgWidth()方法//no.1 获取上传图片的宽高checkImgWidth(fileUrl) {const _that = this;return new Promise((resolve, reject) => {let img = new Image();let res = {};img.onload = function() {res = {width: this.width,height: this.height,};_that.innerW = res.width;_that.innerH = res.height;console.log(_that.innerW,_that.innerH,'inner宽高')resolve(res);};img.src = fileUrl;});},//no.3 获取容器宽高,我这里直接用原生js啦mounted(){let otemWrap = document.getElementsByClassName("content")[0];this.wrapW = otemWrap.clientWidth;this.wrapH = otemWrap.clientHeight;console.log(this.wrapW, this.wrapH, "容器宽高");}//no.4 参数够了, 如何裁剪----裁剪方法封装//🌹 返回容器宽高和图片的定位值getObjectFitSize(contains /* true = contain, false = cover 这个参数就是css的objectfit属性 */,containerWidth,containerHeight,width,height) {var doRatio = width / height;var cRatio = containerWidth / containerHeight;var targetWidth = 0;var targetHeight = 0;var test = contains ? doRatio > cRatio : doRatio < cRatio;if (test) {targetWidth = containerWidth;targetHeight = targetWidth / doRatio;} else {targetHeight = containerHeight;targetWidth = targetHeight * doRatio;}return {width: targetWidth,height: targetHeight,x: (containerWidth - targetWidth) / 2,y: (containerHeight - targetHeight) / 2,};},//no.5 最后一步,什么时候调用裁剪呢!肯定是在获取4个参数后,容器宽度一开始就能获取,所以我们舰艇图片宽度,变化了就调裁剪方法!watch: {innerW: {handler: function(val, oldval) {console.log(this.wrapW, this.wrapH, this.innerW, this.innerH);const {width, height, x, y } = this.getObjectFitSize(false,this.wrapW,this.wrapH,this.innerW,this.innerH);this.wraplw = width;this.wraplh = height;this.innerx = x;this.innery = y;console.log(this.wraplw, this.wraplh, this.innerx, this.innery);deep: true;},},}//okokokokokokokok,最合适的显示上传的图片的宽高有啦<div class="content"><div id="luck" :style="`width:${this.wraplw}px;height:${this.wraplh}px`"><img:src="usedUrl"class="luckimg"v-if="usedUrl":style="`left:${this.innerx}px;top:${this.innery}px `"/></div></div>.content {width: 250px;height: 250px;margin: 0 auto;position: relative;border: rebeccapurple 1px dashed;}#luck {width: 100%;height: 100%;z-index: 2;position: absolute;}.luckimg {width: 100%;height: 100%;position: absolute;// object-fit: cover;}

4、绘制屏幕成图,可直接保存

至此,上传和展示都完成啦,就差最后的生成图片并保存了。对,你没看错,需求想让前端生成图片之后直接和原生开发一样存进相册!被我拒绝了,毕竟这是个h5网页,哪有那么多权限呢??给出的方案就是生成图片以后展示给用户并提示可以保存,最终使用的也是这种,来看看吧

这里用到了html2canvas

//选中要截图的区域<div ref="html2canvas"></div>// 编辑一个截图的触发方法screenHandle() {setTimeout(() => {this.saveImage("html2canvas", "ww");}, 100);},// 实际的保存图片方法saveImage(divText, imgText) {let canvasID = this.$refs[divText];const that = this;let a = document.createElement("a");html2canvas(canvasID).then((canvas) => {var context = canvas.getContext("2d");// 关闭抗锯齿形 这段可以让二维码安稳的在生成后依旧可被手机识别context.mozImageSmoothingEnabled = false;context.webkitImageSmoothingEnabled = false;context.imageSmoothingEnabled = false;let dom = document.body.appendChild(canvas);dom.style.display = "none";a.style.display = "none";document.body.removeChild(dom);let blob = that.dataURLToBlob(dom.toDataURL("image/png"));// console.log(blob.size, "截图的blob大小");//⚠️ yes,这里又压缩了一次,不然的话,有些手机展示不出来这个生成的图片喔compress(blob, function(val) {// console.log(val.size, "截图压缩的大小");const fr = new FileReader();fr.readAsDataURL(val);fr.onload = function() {// 显示图片// console.log(this.result, "最后的base64");that.imgUrl = this.result;// console.log(that.imgUrl, "赋值了");};});//用a标签在pc浏览器可以直接触发保存图片操作,但是移动端无用 // a.setAttribute('href', URL.createObjectURL(blob));// a.setAttribute('download', imgText + '.png');// document.body.appendChild(a);// a.click();// URL.revokeObjectURL(blob);// document.body.removeChild(a);});},

End~,完整的纯前端上传图片并绘制新图结束啦,很多活动页都会用到的,希望有帮助到各位,继续关注后续喔~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。