本篇主要讲述九宫格上传图片
图片编辑实现效果:
图片编辑实现原理:
- 实现九宫格编辑图片可以做成一个组件,使用原生的图片上传方式通过 input 标签上传图片
- 一般图片都挺大,避免用户等待时间过长,使用 canvas 将上传的图片进行压缩
- 每次成功上传一张图片 && 图片总量 < 9 就在图片数组后push 一个待编辑图片
- 由于上传图片的接口需要formData 格式的文件,就需要将压缩后的base64格式的图片 通过dataURLtoBlob blobToFile 这两个函数转换成file文件,此方法不存在浏览器不兼容问题
子组件封装:
<template> <div class="addImg_wrap"> <div class="occupy_img" v-if="!info.imgUrl"> <img src="//nkb-yunpan.oss-cn-beijing.aliyuncs.com/d6de603efa86935328b439f276339c2b.png" alt @click.self.prevent="addImgEvent" class="img1" /> <input class="file" type="file" id="add_input2" accept="image/*" ref="avatarInput" @change="changeImage($event)" /> </div> <div class="real_img" v-if="info.imgUrl"> <img :src="info.imgUrl" alt class="img2" /> <img src="https://nkb-yunpan.oss-cn-beijing.aliyuncs.com/1595a0b56803644173f839f27655754b.png" alt class="close" @click.self.prevent="closeEvent(index)" /> </div> </div> </template> <script> export default { props: { info: { type: Object, default: null }, index: { type: Number, default: null }, isLoading: { type: Boolean, default: null }, }, data() { return {}; }, methods: { addImgEvent() { this.$refs.avatarInput.click(); }, changeImage(e) { const self = this; let imgFile = ""; let file = e.target.files[0]; let filename = file.name; if (file) { let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function() { // 这里的this 指向reader let pic = new Image(); pic.src = this.result; pic.onload = function() { var bitmap = new Image(); bitmap.src = self.compress(pic); self.dataUrl = bitmap.src }; }; // 不加定时器获取不到dataurl setTimeout(() => { console.log('dataUrl'); console.log(self.dataUrl); let blob = self.dataURLtoBlob(self.dataUrl); imgFile = self.blobToFile(blob, filename); let data = new FormData(); data.append("file", imgFile, filename); self.getImgUrl(data); }, 500); } }, // 先将base64转换成blob,再将blob转换成file文件,此方法不存在浏览器不兼容问题 dataURLtoBlob(dataUrl) { var arr = dataUrl.split(","), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, blobToFile(theBlob, fileName) { theBlob.lastModifiedDate = new Date(); theBlob.name = fileName; return theBlob; }, //压缩图片 compress(img) { let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); let width = img.width; let height = img.height; canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0, width, height); //进行压缩 var ndata = canvas.toDataURL("image/jpeg", 0.5); // console.log("已压缩"); return ndata; }, closeEvent(index) { this.$emit("imgDel", index); }, async getImgUrl(data) { this.$emit("loadingEvent", true); const res = await this.fetch.post("Upload/UploadImage",data, "post",); if (res && res.success) { // Toast("上传成功"); this.$emit("imgAdd", { imgUrl: res.result.path, index: this.index,isLoading:false }); } } } }; </script> <style lang="less" scoped> .addImg_wrap { 31%; margin-right: 3%; margin-bottom: 4%; &:nth-child(3n) { margin-right: 0; } .occupy_img, .real_img { 100%; height: 200px; position: relative; .img1 { 100%; height: 206px; box-sizing: border-box; // border: 2px dashed #888888; } .img2 { box-sizing: border-box; 100%; height: 206px; border: 0; } } .close { position: absolute; 32px; height: 32px; top: 0; right: 0; z-index: 9; } .file { opacity: 0; 1px; height: 1px; } } </style>
父组件调用:
<template> <div class="nineImgs_wrap"> <div class="edit_img"> <addImgComponent v-for="(item,index) in imgList" :key="index" :info.sync="item" @imgDel="imgDel" @imgAdd="imgAdd" @loadingEvent="loadingEvent" :index="index" :isLoading="isLoading" ></addImgComponent> </div> <div class="loading" v-if="isLoading"> <van-loading type="spinner" size="30px" vertical></van-loading> </div> </div> </template> <script> import addImgComponent from "@/components/addImg.vue"; export default { name: "nineImgs", components: { addImgComponent }, data() { return { imgList: [ { imgUrl: "" } ], isLoading: false }; }, methods: { loadingEvent(val){ this.isLoading = val }, imgAdd(val) { this.isLoading = val.isLoading this.imgList.forEach((v, i) => { if (i === val.index) { v.imgUrl = val.imgUrl; } }); const a = { imgUrl: null }; this.imgList.push(a); }, imgDel(d) { this.imgList.forEach((v, i) => { if (i === d) { this.imgList.splice(i, 1); } }); } } }; </script> <style lang="less" scoped> .nineImgs_wrap { 100%; padding: 30px; font-size: 18px; .edit_img { display: flex; flex-wrap: wrap; margin-top: 20px; .real_img, .occupy_img .img1 { height: 200px !important; } } .loading{ 100%; } } </style>
分享一刻:
Safari 浏览器开始完全禁用第三方 Cookie,本文分析了有何影响,以及如何在没有 Cookie 的情况下,获取浏览器的指纹。