ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue封装原生的可预览裁剪上传图片插件H5,PC端都可以使用

2022-07-09 12:34:17  阅读:163  来源: 互联网

标签:插件 vue console log refs 50% H5 上传 event


思路:1.先做出一个上传的图片的上传区
  <!-- 上传区 -->
      <label for="fileUp">
        <div class="upBorder">
          <img src="../assets/add.png" alt="" />
          <input
            ref="fileUp"
            type="file"
            id="fileUp"
            accept="image"
            style="display: none"
            @change="upload()"
          />
        </div>
      </label>

  

  upload() {
      let that = this;
      console.log(this.$refs.fileUp.files);
      if (this.$refs.fileUp.files.length != 0) {
        const reader = new FileReader();
        reader.readAsDataURL(this.$refs.fileUp.files[0]);
        reader.onload = function () {
          const img = new Image();
          img.src = reader.result;
          that.fileList.push(reader.result);
          that.$refs.fileUp.value = null; //上传后重置上传input的value,这样才能同时上传相同的图片
          console.log(reader.result);
        };
        this.upLodaOk = true;
      }
    },

  给上传图片的input绑定上ref属性然后通过FileReader构造函数获取上传的文件。

2.完成已上传文件的预览区域

 <!-- 预览区域 -->
      <div
        class="preView"
        v-for="(i, index) in fileList"
        :key="index"
        ref="preList"
      >
        <div class="fileList" v-if="upLodaOk">
          <img
            src="../assets/remove.png"
            alt=""
            class="remove"
            @click="removeProp(index)"
          />
          <img
            :src="fileList[index]"
            alt=""
            class="img"
            @click="cut(index)"
            ref="imgitem"
          />
        </div>
      </div>

  在upload方法中将通过FileReader构造函数获取上传的文件push到fileList数组中然后遍历渲染出已经上传的图片列表,并且给每一个图片绑定ref属性。

3.完成图片删除的功能

<!-- 删除弹窗 -->
    <div
      class="prop"
      :style="{
        height: this.windowHeight + 'px',
        width: this.windowWidth + 'px',
      }"
      v-if="show"
    >
      <div class="text">
        <img
          src="../assets/remove.png"
          alt=""
          class="close"
          @click="removePropClose()"
        />
        <div>要删除这张照片吗</div>
        <div class="action">
          <button class="btn green" @click="removePropClose()">取消</button>
          <button class="btn blue" @click="remove()">确定</button>
        </div>
      </div>
    </div>
   removeProp(index) {
      //v-for循环中的ref是个数组,根据index来取每一个对应的dom元素
      this.removeIndex = index;
      this.show = true;
    },
    removePropClose() {
      this.show = false;
    },
    remove() {
      this.fileList.splice(this.removeIndex, 1);
      this.$refs.fileUp.value = null; //删除后重置上传input的value,这样才能同时上传相同的图片
      console.log(this.$refs.fileUp.value);
      this.show = false;
    },

点击预览图片上的x会触发删除确认弹窗,在removeProp方法中将要删除的图片的Index接收并存储的removeIndex变量中,remove方法中将fileList数组中对应索引的元素去掉并且重置一下上传属性,也可以在每次上传后重置,并且关闭弹窗

4.完成上传时的剪裁功能

   <!-- 裁剪蒙层 -->
    <div
      class="prop center"
      v-if="cutProp"
      :style="{
        height: this.windowHeight + 'px',
        width: this.windowWidth + 'px',
      }"
    >
      <div v-html="pre" ref="preimg" class="imgContent"></div>
      <div class="cutHandler">
        <button class="btn green" @click="cancel()">取消</button>
        <button class="btn blue" @click="qdcut()">剪裁</button>
      </div>
    </div>
   cut(index) {
      this.selIndex = index;
      this.pre = `<img
            src="${this.fileList[index]}"
            alt=""
            class='cutImg'
          />`;
      this.cutProp = true;
      console.log(this.$refs);
      this.$nextTick(function () {
        console.log(this.$refs.preimg.firstChild); //使用nextTick,dom更新完成后才能获取到子节点
        this.myCropper = new Cropper(this.$refs.preimg.firstChild, {
          aspectRatio: 1 / 1,
          dragMode: "move",
          outputType: "png", //防止图片背景变黑
          crop(event) {
            console.log(event.detail.x);
            console.log(event.detail.y);
            console.log(event.detail.width);
            console.log(event.detail.height);
            console.log(event.detail.rotate);
            console.log(event.detail.scaleX);
            console.log(event.detail.scaleY);
          },
        });
      });
    },
    qdcut() {
      let cropBox = this.myCropper.getCropBoxData();
      console.log(this.myCropper.getCropBoxData()); //打印裁剪数据
      let cropCanvas = this.myCropper.getCroppedCanvas({
        width: cropBox.width,
        height: cropBox.height,
      }); //使用画布画出裁剪后的图片
      let imgData = cropCanvas.toDataURL(); //导出裁剪后图片的数据
      console.log(imgData);
      this.fileList.splice(this.selIndex, 1, imgData);
      console.log(this.fileList);
      this.cutProp = false;
    }, //确定裁剪
    cancel() {
      this.cutProp = false;
    }, //取消裁剪

  因为本次封装的是预览时裁剪的功能,所以裁剪的是点击预览列表中的文件触发的,cut方法将选择的图片的index存储selIndex变量中,然后通过v-html指令在剪裁弹窗中加载出对应的图片来进行裁剪,裁剪使用cropper.js来进行的,注意使用时要在this.$nextTick方法的回调中来进行剪裁函数的初始化,这样才能获取到通过v-html指令插入的图片。

  选择合适的裁剪尺寸后点击确认才加调用qdcut方法,通过cropper.js的内置方法getCropBoxData()获取剪裁的数据,通过getCroppedCanvas()传入对应的数据然后导出剪裁后的图片,将fileList中对应的元素替换即可完成

6.下面附上整个代码,可以直接拿去使用:

  1 <template>
  2   <div>
  3     <!-- 裁剪蒙层 -->
  4     <div
  5       class="prop center"
  6       v-if="cutProp"
  7       :style="{
  8         height: this.windowHeight + 'px',
  9         width: this.windowWidth + 'px',
 10       }"
 11     >
 12       <div v-html="pre" ref="preimg" class="imgContent"></div>
 13       <div class="cutHandler">
 14         <button class="btn green" @click="cancel()">取消</button>
 15         <button class="btn blue" @click="qdcut()">剪裁</button>
 16       </div>
 17     </div>
 18     <!-- 删除弹窗 -->
 19     <div
 20       class="prop"
 21       :style="{
 22         height: this.windowHeight + 'px',
 23         width: this.windowWidth + 'px',
 24       }"
 25       v-if="show"
 26     >
 27       <div class="text">
 28         <img
 29           src="../assets/remove.png"
 30           alt=""
 31           class="close"
 32           @click="removePropClose()"
 33         />
 34         <div>要删除这张照片吗</div>
 35         <div class="action">
 36           <button class="btn green" @click="removePropClose()">取消</button>
 37           <button class="btn blue" @click="remove()">确定</button>
 38         </div>
 39       </div>
 40     </div>
 41     <!-- 上传区域 -->
 42     <div class="upContent">
 43       <!-- 预览区域 -->
 44       <div
 45         class="preView"
 46         v-for="(i, index) in fileList"
 47         :key="index"
 48         ref="preList"
 49       >
 50         <div class="fileList" v-if="upLodaOk">
 51           <img
 52             src="../assets/remove.png"
 53             alt=""
 54             class="remove"
 55             @click="removeProp(index)"
 56           />
 57           <img
 58             :src="fileList[index]"
 59             alt=""
 60             class="img"
 61             @click="cut(index)"
 62             ref="imgitem"
 63           />
 64         </div>
 65       </div>
 66       <!-- 上传区 -->
 67       <label for="fileUp">
 68         <div class="upBorder">
 69           <img src="../assets/add.png" alt="" />
 70           <input
 71             ref="fileUp"
 72             type="file"
 73             id="fileUp"
 74             accept="image"
 75             style="display: none"
 76             @change="upload()"
 77           />
 78         </div>
 79       </label>
 80     </div>
 81   </div>
 82 </template>
 83 <script>
 84 import Cropper from "cropperjs";
 85 import "cropperjs/dist/cropper.css";
 86 export default {
 87   name: "upload",
 88   data() {
 89     return {
 90       cutProp: false,
 91       pre: "", //准备剪裁的图片
 92       selIndex: "", //选择照片的索引
 93       removeIndex: "", //准备删除的照片的索引
 94       show: false, //删除弹出层
 95       myCropper: null,
 96       afterImg: "",
 97       ingData: null,
 98       upLodaOk: false, //是否展示预览列表
 99       fileList: [], //已经上传图片的列表
100     };
101   },
102   methods: {
103     upload() {
104       let that = this;
105       console.log(this.$refs.fileUp.files);
106       if (this.$refs.fileUp.files.length != 0) {
107         const reader = new FileReader();
108         reader.readAsDataURL(this.$refs.fileUp.files[0]);
109         reader.onload = function () {
110           const img = new Image();
111           img.src = reader.result;
112           that.fileList.push(reader.result);
113           that.$refs.fileUp.value = null; //上传后重置上传input的value,这样才能同时上传相同的图片
114           console.log(reader.result);
115         };
116         this.upLodaOk = true;
117       }
118     },
119     removeProp(index) {
120       //v-for循环中的ref是个数组,根据index来取每一个对应的dom元素
121       this.removeIndex = index;
122       this.show = true;
123     },
124     removePropClose() {
125       this.show = false;
126     },
127     remove() {
128       this.fileList.splice(this.removeIndex, 1);
129       this.$refs.fileUp.value = null; //删除后重置上传input的value,这样才能同时上传相同的图片
130       console.log(this.$refs.fileUp.value);
131       this.show = false;
132     },
133     cut(index) {
134       this.selIndex = index;
135       this.pre = `<img
136             src="${this.fileList[index]}"
137             alt=""
138             class='cutImg'
139           />`;
140       this.cutProp = true;
141       console.log(this.$refs);
142       this.$nextTick(function () {
143         console.log(this.$refs.preimg.firstChild); //使用nextTick,dom更新完成后才能获取到子节点
144         this.myCropper = new Cropper(this.$refs.preimg.firstChild, {
145           aspectRatio: 1 / 1,
146           dragMode: "move",
147           outputType: "png", //防止图片背景变黑
148           crop(event) {
149             console.log(event.detail.x);
150             console.log(event.detail.y);
151             console.log(event.detail.width);
152             console.log(event.detail.height);
153             console.log(event.detail.rotate);
154             console.log(event.detail.scaleX);
155             console.log(event.detail.scaleY);
156           },
157         });
158       });
159     },
160     qdcut() {
161       let cropBox = this.myCropper.getCropBoxData();
162       console.log(this.myCropper.getCropBoxData()); //打印裁剪数据
163       let cropCanvas = this.myCropper.getCroppedCanvas({
164         width: cropBox.width,
165         height: cropBox.height,
166       }); //使用画布画出裁剪后的图片
167       let imgData = cropCanvas.toDataURL(); //导出裁剪后图片的数据
168       console.log(imgData);
169       this.fileList.splice(this.selIndex, 1, imgData);
170       console.log(this.fileList);
171       this.cutProp = false;
172     }, //确定裁剪
173     cancel() {
174       this.cutProp = false;
175     }, //取消裁剪
176   },
177   mounted() {},
178   computed: {
179     windowWidth() {
180       return document.documentElement.clientWidth;
181     },
182     windowHeight() {
183       return document.documentElement.clientHeight;
184     },
185   }, //监听屏幕的宽度和高度
186 };
187 </script>
188 <style>
189 .upBorder {
190   width: 8rem;
191   height: 8rem;
192   border: 1px silver dashed;
193   display: flex;
194   justify-content: center;
195   align-items: center;
196 }
197 .upContent {
198   display: flex;
199   justify-content: center;
200   align-items: center;
201 }
202 .img {
203   width: 8rem;
204   height: 8rem;
205 }
206 
207 .fileList {
208   position: relative;
209   display: flex;
210   flex-direction: column;
211   justify-content: center;
212   align-items: center;
213 }
214 .remove {
215   position: absolute;
216   width: 1rem;
217   height: 1rem;
218   top: 0rem;
219   right: 0rem;
220   cursor: pointer;
221 }
222 .prop {
223   vertical-align: middle;
224   position: fixed;
225   top: 0;
226   left: 0;
227   z-index: 999;
228   background-color: rgba(0, 0, 0, 0.7);
229 }
230 .text {
231   border-radius: 0.2rem;
232   top: 50%;
233   left: 50%;
234   -webkit-transform: translate3d(-50%, -50%, 0);
235   transform: translate3d(-50%, -50%, 0);
236   position: fixed;
237   z-index: 1000;
238   color: black;
239   text-align: center;
240   background-color: #fff;
241   padding: 2rem 4rem;
242   white-space: nowrap;
243 }
244 .close {
245   position: absolute;
246   top: 0.3rem;
247   right: 0.3rem;
248   width: 1rem;
249   height: 1rem;
250 }
251 .action {
252   display: flex;
253   justify-content: space-between;
254   align-items: center;
255   margin-top: 1rem;
256 }
257 .btn {
258   font-size: 0.12rem;
259   color: #fff;
260   padding: 0.2rem 0.8rem;
261 }
262 .blue {
263   background-color: #1989fa;
264   border: 1px solid #1989fa;
265 }
266 .green {
267   background-color: #07c160;
268   border: 1px solid #07c160;
269 }
270 .cropper-point.point-se {
271   width: 5px;
272   height: 5px;
273 }
274 .cropper {
275   position: fixed;
276   top: 0;
277   z-index: 999;
278 }
279 
280 /* .cropper-container{
281    top: 50%;
282   left: 50%;
283   -webkit-transform: translate3d(-50%, -50%, 0);
284   transform: translate3d(-50%, -50%, 0);
285 } */
286 .imgContent {
287   width: 16rem;
288   height: 16rem;
289   display: inline-block;
290   /* top: 50%;
291   left: 50%;
292   -webkit-transform: translate3d(-50%, -50%, 0);
293   transform: translate3d(-50%, -50%, 0); */
294 }
295 .cutImg {
296   display: block;
297   max-width: 100%;
298 }
299 .center {
300   display: flex;
301   flex-direction: column;
302   justify-content: center;
303   align-items: center;
304 }
305 .cropper-bg {
306   background: none;
307 }
308 .cutHandler {
309   margin-top: 2rem;
310   width: 16rem;
311   text-align: center;
312   display: flex;
313   justify-content: space-between;
314   align-items: center;
315 }
316 .cropper-modal {
317   background: rgba(0, 0, 0, 0);
318 }
319 </style>

 运行截图:

 

 

 

 

 

 H5,PC端都可以使用  

标签:插件,vue,console,log,refs,50%,H5,上传,event
来源: https://www.cnblogs.com/SadicZhou/p/16460609.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有