思路:1.先做出一个上传的图片的上传区

  1. <!-- 上传区 -->
  2. <label for="fileUp">
  3. <div class="upBorder">
  4. <img src="../assets/add.png" alt="" />
  5. <input
  6. ref="fileUp"
  7. type="file"
  8. id="fileUp"
  9. accept="image"
  10. style="display: none"
  11. @change="upload()"
  12. />
  13. </div>
  14. </label>

  

  1. upload() {
  2. let that = this;
  3. console.log(this.$refs.fileUp.files);
  4. if (this.$refs.fileUp.files.length != 0) {
  5. const reader = new FileReader();
  6. reader.readAsDataURL(this.$refs.fileUp.files[0]);
  7. reader.onload = function () {
  8. const img = new Image();
  9. img.src = reader.result;
  10. that.fileList.push(reader.result);
  11. that.$refs.fileUp.value = null; //上传后重置上传input的value,这样才能同时上传相同的图片
  12. console.log(reader.result);
  13. };
  14. this.upLodaOk = true;
  15. }
  16. },

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

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

  1. <!-- 预览区域 -->
  2. <div
  3. class="preView"
  4. v-for="(i, index) in fileList"
  5. :key="index"
  6. ref="preList"
  7. >
  8. <div class="fileList" v-if="upLodaOk">
  9. <img
  10. src="../assets/remove.png"
  11. alt=""
  12. class="remove"
  13. @click="removeProp(index)"
  14. />
  15. <img
  16. :src="fileList[index]"
  17. alt=""
  18. class="img"
  19. @click="cut(index)"
  20. ref="imgitem"
  21. />
  22. </div>
  23. </div>

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

3.完成图片删除的功能

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

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

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

  1. <!-- 裁剪蒙层 -->
  2. <div
  3. class="prop center"
  4. v-if="cutProp"
  5. :style="{
  6. height: this.windowHeight + 'px',
  7. width: this.windowWidth + 'px',
  8. }"
  9. >
  10. <div v-html="pre" ref="preimg" class="imgContent"></div>
  11. <div class="cutHandler">
  12. <button class="btn green" @click="cancel()">取消</button>
  13. <button class="btn blue" @click="qdcut()">剪裁</button>
  14. </div>
  15. </div>
  1. cut(index) {
  2. this.selIndex = index;
  3. this.pre = `<img
  4. src="${this.fileList[index]}"
  5. alt=""
  6. class='cutImg'
  7. />`;
  8. this.cutProp = true;
  9. console.log(this.$refs);
  10. this.$nextTick(function () {
  11. console.log(this.$refs.preimg.firstChild); //使用nextTick,dom更新完成后才能获取到子节点
  12. this.myCropper = new Cropper(this.$refs.preimg.firstChild, {
  13. aspectRatio: 1 / 1,
  14. dragMode: "move",
  15. outputType: "png", //防止图片背景变黑
  16. crop(event) {
  17. console.log(event.detail.x);
  18. console.log(event.detail.y);
  19. console.log(event.detail.width);
  20. console.log(event.detail.height);
  21. console.log(event.detail.rotate);
  22. console.log(event.detail.scaleX);
  23. console.log(event.detail.scaleY);
  24. },
  25. });
  26. });
  27. },
  28. qdcut() {
  29. let cropBox = this.myCropper.getCropBoxData();
  30. console.log(this.myCropper.getCropBoxData()); //打印裁剪数据
  31. let cropCanvas = this.myCropper.getCroppedCanvas({
  32. width: cropBox.width,
  33. height: cropBox.height,
  34. }); //使用画布画出裁剪后的图片
  35. let imgData = cropCanvas.toDataURL(); //导出裁剪后图片的数据
  36. console.log(imgData);
  37. this.fileList.splice(this.selIndex, 1, imgData);
  38. console.log(this.fileList);
  39. this.cutProp = false;
  40. }, //确定裁剪
  41. cancel() {
  42. this.cutProp = false;
  43. }, //取消裁剪

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

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

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

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

运行截图:

 H5,PC端都可以使用
 

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

  1. Jcrop+uploadify+php实现上传头像预览裁剪

    最近由于项目需要,所以做了一个上传头像预览并且可以预览裁剪的功能,大概思路是上传的图片先保存到服务器,然后通过ajax从服务器获取到图片信息,再利用Jcrop插件进行裁剪,之后通过PHP获取到的四个裁 ...

  2. previewImage.js图片预览缩放保存插件

    previewImage.js好用的图片预览缩放保存插件

  3. 上传预览图片的插件jquery-fileupload

    上传预览图片的插件jquery-fileupload github地址:https://github.com/blueimp/jQuery-File-Upload 中文文档:http://www.jq ...

  4. [RN] React Native 使用 图片预览和放大 插件 react-native-image-zoom-viewer 过程中,放大报错问题

    React Native 使用 图片预览和放大 插件 react-native-image-zoom-viewer 过程中,放大报错问题 报错如下: Cannot record touch end w ...

  5. vue项目上传Github预览

    最近在用Vue仿写cnode社区,想要上传到github,并通过Github pages预览,在这个过程中遇到了一些问题,因此写个笔记,以便查阅. 完成Vue项目以后,在上传到github之前,需要修 ...

  6. 在 vue 中使用 vieiwer 图片预览插件

    https://blog.csdn.net/WestLonly/article/details/79801800?utm_source=blogxgwz0 首先,感谢原作者 官网链接 github地址 ...

  7. vue图片点击放大预览

    第一种:viewerjs使用介绍(PC.移动端都兼容) 1.先安装依赖 npm install v-viewer --save 2.main.js内引用并注册调用 //main.js import V ...

  8. webform的原生操作图片预览和上传

    1.使用input标签进行图片操作,input的标签有一个accept属性,accept 属性只能与 <input type="file"> 配合使用.它规定能够通过文 ...

  9. 【VUE】图片预览放大缩小插件

    From: https://www.jianshu.com/p/e3350aa1b0d0 在看项目时,突然看到预览图片的弹窗,感觉好僵硬,不能放大,不能切换,于是便在网上找下关于图片预览的插件,有找到 ...

随机推荐

  1. Abp集成HangFire

    简要说明 后台作业在系统开发的过程当中,是比较常用的功能.因为总是有一些长耗时的任务,而这些任务我们不是立即响应的,例如 Excel 文档导入.批量发送短信通知等. ABP vNext 提供了后台作业 ...

  2. vue 常见指令

    vue 常见的指令 v-bind:单向绑定解析表达式可简写为  :xxxx v-model: 双向数据绑定 v-for : 遍历数组/对象/字符串 v-on :绑定事件监听,.可简写为@ v-if : ...

  3. NLP教程(3) | 神经网络与反向传播

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www.showmeai.tech/article-det ...

  4. 利用VTK和PyQt5对医学体数据进行渲染并展示

    简介 在一些医学相关的简单的项目(也许是学生的作业?毕业设计?)中,有时候可能需要集成一些可视化的功能,本文简单介绍一下,如何利用PyQt5和VTK来渲染体数据(三维数据),并集成进PyQt的UI框架 ...

  5. HCNP Routing&Switching之RSTP保护

    前文我们了解了RSTP相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16240348.html:今天我们来聊一聊RSTP保护相关话题: 我们知道RST ...

  6. MySQL 的 EXPLAIN 语句及用法

    在MySQL中 DESCRIBE 和 EXPLAIN 语句是相同的意思.DESCRIBE 语句多用于获取表结构,而 EXPLAIN 语句用于获取查询执行计划(用于解释MySQL如何执行查询语句). 通 ...

  7. 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  8. 树形dp基础

    今天来给大家讲一下数形dp基础 树形dp常与树上问题(lca.直径.重心)结合起来 而这里只讲最最基础的树上dp 1.选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程 ...

  9. 测试open

    // 此处,返回的 undefined 是 JS 中的一个值 return undefined } // 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同 const add ...

  10. JNPF.java前后端分离框架,SpringBoot+SpringCloud开发微服务平台

    JNPF.java版本采用全新的前后端分离架构模式.前后端分离已成为互联网项目开发的业界标准开发方式,通过 nginx+tomcat 等方式有效的进行解耦合,并且前后端分离会为以后的大型分布式架构.弹 ...