vue封装原生的可预览裁剪上传图片插件H5,PC端都可以使用
思路: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>
运行截图:
vue封装原生的可预览裁剪上传图片插件H5,PC端都可以使用的更多相关文章
- Jcrop+uploadify+php实现上传头像预览裁剪
最近由于项目需要,所以做了一个上传头像预览并且可以预览裁剪的功能,大概思路是上传的图片先保存到服务器,然后通过ajax从服务器获取到图片信息,再利用Jcrop插件进行裁剪,之后通过PHP获取到的四个裁 ...
- previewImage.js图片预览缩放保存插件
previewImage.js好用的图片预览缩放保存插件
- 上传预览图片的插件jquery-fileupload
上传预览图片的插件jquery-fileupload github地址:https://github.com/blueimp/jQuery-File-Upload 中文文档:http://www.jq ...
- [RN] React Native 使用 图片预览和放大 插件 react-native-image-zoom-viewer 过程中,放大报错问题
React Native 使用 图片预览和放大 插件 react-native-image-zoom-viewer 过程中,放大报错问题 报错如下: Cannot record touch end w ...
- vue项目上传Github预览
最近在用Vue仿写cnode社区,想要上传到github,并通过Github pages预览,在这个过程中遇到了一些问题,因此写个笔记,以便查阅. 完成Vue项目以后,在上传到github之前,需要修 ...
- 在 vue 中使用 vieiwer 图片预览插件
https://blog.csdn.net/WestLonly/article/details/79801800?utm_source=blogxgwz0 首先,感谢原作者 官网链接 github地址 ...
- vue图片点击放大预览
第一种:viewerjs使用介绍(PC.移动端都兼容) 1.先安装依赖 npm install v-viewer --save 2.main.js内引用并注册调用 //main.js import V ...
- webform的原生操作图片预览和上传
1.使用input标签进行图片操作,input的标签有一个accept属性,accept 属性只能与 <input type="file"> 配合使用.它规定能够通过文 ...
- 【VUE】图片预览放大缩小插件
From: https://www.jianshu.com/p/e3350aa1b0d0 在看项目时,突然看到预览图片的弹窗,感觉好僵硬,不能放大,不能切换,于是便在网上找下关于图片预览的插件,有找到 ...
随机推荐
- Abp集成HangFire
简要说明 后台作业在系统开发的过程当中,是比较常用的功能.因为总是有一些长耗时的任务,而这些任务我们不是立即响应的,例如 Excel 文档导入.批量发送短信通知等. ABP vNext 提供了后台作业 ...
- vue 常见指令
vue 常见的指令 v-bind:单向绑定解析表达式可简写为 :xxxx v-model: 双向数据绑定 v-for : 遍历数组/对象/字符串 v-on :绑定事件监听,.可简写为@ v-if : ...
- NLP教程(3) | 神经网络与反向传播
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www.showmeai.tech/article-det ...
- 利用VTK和PyQt5对医学体数据进行渲染并展示
简介 在一些医学相关的简单的项目(也许是学生的作业?毕业设计?)中,有时候可能需要集成一些可视化的功能,本文简单介绍一下,如何利用PyQt5和VTK来渲染体数据(三维数据),并集成进PyQt的UI框架 ...
- HCNP Routing&Switching之RSTP保护
前文我们了解了RSTP相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16240348.html:今天我们来聊一聊RSTP保护相关话题: 我们知道RST ...
- MySQL 的 EXPLAIN 语句及用法
在MySQL中 DESCRIBE 和 EXPLAIN 语句是相同的意思.DESCRIBE 语句多用于获取表结构,而 EXPLAIN 语句用于获取查询执行计划(用于解释MySQL如何执行查询语句). 通 ...
- 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 树形dp基础
今天来给大家讲一下数形dp基础 树形dp常与树上问题(lca.直径.重心)结合起来 而这里只讲最最基础的树上dp 1.选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程 ...
- 测试open
// 此处,返回的 undefined 是 JS 中的一个值 return undefined } // 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同 const add ...
- JNPF.java前后端分离框架,SpringBoot+SpringCloud开发微服务平台
JNPF.java版本采用全新的前后端分离架构模式.前后端分离已成为互联网项目开发的业界标准开发方式,通过 nginx+tomcat 等方式有效的进行解耦合,并且前后端分离会为以后的大型分布式架构.弹 ...