1

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

 1 year ago
source link: https://www.cnblogs.com/SadicZhou/p/16460609.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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>

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK