2/16 Vue 上传图片并预览的实现 ( 一 )
写在前面
现在还没有上传功能 只差个axios
明天继续写
今天先放个代码
这个东西可以直接复制用
但是上传的文件位置和渲染出来的不一样,估计是底层的东西问题,我没有解决方案 ( for 循环的机制 )
2/17 补充 现在写完了
https://www.cnblogs.com/WaterMealone/p/14409454.html
1 <!DOCTYPE html> 2 <html lang="zh-CN"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>Document</title> 7 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> 8 <!-- 引用一个css库 --> 9 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"> 10 </head> 11 12 <body> 13 <div id="app"> 14 <div class="container"> 15 16 <div class="title-container"> 17 <span>上传文件</span> 18 </div> 19 20 <div class="upload-box"> 21 <div class="drag-box" ref="dragBox" :class="isDrag? 'draging-drag-box':'' "> 22 <label> 23 <div class="icon-container"> 24 <i class="fa fa-file" :class="isDrag? 'draging-fa-file': ''"></i> 25 </div> 26 <div class="label-text-container"> 27 <span :class="isDrag? 'draging-label-text-container':'' ">请将文件拖动至此</span> 28 <br> 29 <span :class="isDrag? 'draging-label-text-container':'' ">或者单击上传</span> 30 </div> 31 <input type="file" accept="image/jepg, image/png" name="pictures" 32 @change="storepreFiles($event.target)" multiple> 33 </label> 34 </div> 35 36 <div class="show-file-box" v-if=" files.length == 0 ? false : true"> 37 38 <div class="text-container"> 39 <span>上传列表</span> 40 <span>{{updateState}} / {{preFilesLength}}</span> 41 </div> 42 <!-- 渲染出来的情况 有一个进度条 --> 43 <div class="pre-upload-bar"> 44 <div> 45 <span>列表加载进度 {{(updateState / preFilesLength).toFixed(1) *100}} %</span> 46 </div> 47 <div class="pre-upload-bar-done" 48 :style="{ width: ( updateState / preFilesLength ) *100 + '%' }"> 49 </div> 50 </div> 51 <!-- <div v-if="updateState === preFilesLength ? true : false"> --> 52 53 <ul class="pre-upload-list"> 54 <transition-group tag="li" name="list"> 55 <li class="pre-upload-file" v-for="file in preFiles" :key="file.name"> 56 <div class="review"> 57 <!-- 图片预览 --> 58 <div class="review-image-container"> 59 <img class="review-image" :src="file.src"> 60 </div> 61 62 <div class="review-file-name-container"> 63 <span class="file-name"> {{ file.name }}</span> 64 </div> 65 <div class="progress"> 66 <div class="progress-done" :style="{ width: file.index + '%' }"></div> 67 </div> 68 <span class="percent">{{ file.index }}%</span> 69 <input class="select-box" check type="checkbox" name="select" :value="file.name" 70 :checked="file.isChecked" @change="doSelect(file.name)" ref="select" /> 71 </div> 72 </li> 73 </transition-group> 74 </ul> 75 76 77 <hr color="lightpink" style="margin: 10px 8px;"> 78 <!-- 选择按钮 --> 79 <div class="bottom-select"> 80 <span class="bottom-select-button" @click="seletAll">{{ select }}</span> 81 <div class="bottom-select-info"> 82 <div> <span>已选</span> <span class="span-special" 83 :style="{'color': showSize() > 15 ? 'red':'green'}">{{showSelect()}} </span> 84 <span>/{{preFilesLength}}</span> 85 </div> 86 <div> <span class="span-special" :style="{'color': showSize() > 15 ? 'red':'green'}">{{ 87 showSize() }} </span> <span>/ {{showAllSize()}} mb </span></div> 88 </div> 89 </div> 90 91 <div class="bottom-upload"> 92 <span>上传</span> 93 </div> 94 95 96 </div> 97 </div> 98 99 </div> 100 101 </div> 102 </body> 103 104 <script> 105 var vm = new Vue({ 106 el: '#app', 107 data() { 108 return { 109 // 预展示的图片对象数组 110 preFiles: [], 111 // preFiles: (function (num) { 112 // var temp = new Array 113 // for (let i = 0; i < num; i++) { 114 // temp.push(0) 115 // } 116 // return temp 117 // })(9), 118 119 preFilesLength: 0, 120 // 这个是渲染list的过程 渲染到第几个li 121 updateState: 0, 122 123 // 真正要上传的图片文件 124 files: [], 125 126 // 选择上传的文件 127 select: "全选", 128 129 // 是否进行拖动事件 130 isDrag: false 131 } 132 }, 133 updated() { 134 }, 135 mounted: function () { 136 var dragBox = this.$refs.dragBox; 137 dragBox.addEventListener('dragenter', this.onDrag, false); 138 dragBox.addEventListener('dragover', this.onDrag, false); 139 dragBox.addEventListener('dragleave', () => { this.isDrag = false; }, false); 140 dragBox.addEventListener('drop', this.onDrop, false); 141 }, 142 watch: { 143 // 通过对 preFiles 监听 实现简单加载文件进度条 144 preFiles: { 145 handler: 'updateS' 146 } 147 }, 148 methods: { 149 storepreFiles(obj) { 150 // 获取input里面的文件组 151 var fileList = obj.files; 152 // 先判定有没有重复提交的文件 可以加判断条件 153 for (let i = 0; i < fileList.length; i++) { 154 for (let j = 0; j < this.preFiles.length; j++) { 155 if (this.preFiles[j].name === fileList[i].name) { 156 alert("有文件重复") 157 return 158 } 159 } 160 } 161 162 this.preFilesLength = this.preFilesLength + fileList.length 163 164 // 这样防止变成 两个Filelist 对象 组合 165 for (var i = 0; i < fileList.length; i++) { 166 this.files = this.files.concat(fileList[i]) 167 } 168 var vue = this 169 //对文件组进行遍历,可以到控制台打印出fileList去看看 170 for (let i = 0; i < fileList.length; i++) { 171 172 function uploadFile(file) { 173 return new Promise(function (resolve, reject) { 174 let reader = new FileReader() 175 reader.readAsDataURL(file) 176 reader.onload = function () { 177 resolve(this.result) 178 } 179 }) 180 } 181 uploadFile(fileList[i]).then(function (result) { 182 console.group(i) 183 console.log(event) 184 console.log(fileList[i]) 185 console.groupEnd() 186 // vue.preFiles.splice(i, 0, { name: fileList[i].name, size: fileList[i].size, index: 0, }) 187 vue.preFiles.push({ name: fileList[i].name, size: fileList[i].size, index: 0, src: result, isChecked: true }) 188 }) 189 } 190 }, 191 192 // 渲染列表的参数 193 updateS() { 194 this.updateState = this.updateState + 1 195 }, 196 197 findPreFile(name) { 198 let that = this 199 return this.preFiles.find((item, index) => { 200 return item.name === name; 201 }) 202 203 }, 204 205 // 点击 选择框 和 全选 206 doSelect(name) { 207 this.preFiles.forEach(element => { 208 if (element.name == name) { 209 element.isChecked = !element.isChecked 210 } 211 212 }); 213 214 }, 215 seletAll() { 216 if (this.$refs.select.find(item => item.checked == false)) { 217 console.log(this.$refs.select) 218 this.preFiles.forEach(element => { 219 element.isChecked = true 220 }) 221 } 222 223 }, 224 225 // 显示 选中个数 和 显示 选中的文件大小 226 showSelect() { 227 let num = 0 228 this.preFiles.forEach(element => { 229 if (element.isChecked == true) { 230 num++; 231 } 232 }); 233 return num 234 }, 235 236 showSize() { 237 let size = 0 238 this.preFiles.forEach(element => { 239 if (element.isChecked == true) { 240 size = size + element.size 241 } 242 }); 243 return (size / Math.pow(2, 20)).toFixed(2) 244 }, 245 246 showAllSize() { 247 let size = 0 248 this.preFiles.forEach(element => { 249 250 size = size + element.size 251 }); 252 return (size / Math.pow(2, 20)).toFixed(2) 253 254 }, 255 256 // 拖动文件上传 257 onDrag: function (e) { 258 this.isDrag = true; 259 e.stopPropagation(); 260 e.preventDefault(); 261 // var dragBox = this.$refs.dragBox; 262 // var faFile = this.$refs.faFile; 263 // var textContainer = this.$refs.textContainer; 264 265 // dragBox.onmouseover(); 266 // console.log(dragBox) 267 268 }, 269 270 onDragLeave(e) { 271 272 }, 273 274 onDrop: function (e) { 275 this.isDrag = false; 276 e.stopPropagation(); 277 e.preventDefault(); 278 var dt = e.dataTransfer; 279 this.storepreFiles(dt); 280 } 281 } 282 }); 283 284 </script> 285 286 <style> 287 span { 288 font-weight: 700; 289 font: bolder; 290 } 291 292 .container { 293 width: 450px; 294 /* background-color: rgb(195, 209, 228); */ 295 box-shadow: 2px 2px 2px 2px rgba(68, 68, 68, 0.2); 296 border-radius: 10px; 297 padding: 20px; 298 } 299 300 .upload-box { 301 /* width: 400px; */ 302 /* height: 400px; */ 303 304 } 305 306 .title-container { 307 margin: 10px 8px 20px 8px; 308 font-size: 20px; 309 310 border-radius: 5px; 311 background: linear-gradient(to right, rgb(112, 158, 242), rgb(255, 255, 255)); 312 color: white; 313 } 314 315 .drag-box { 316 padding: 20px; 317 margin: 10px auto; 318 width: 380px; 319 border-radius: 10px; 320 border: 5px dashed rgba(112, 155, 248, 0.7); 321 text-align: center; 322 transition: all linear 0.1s; 323 } 324 325 .label-text-container { 326 margin: 20px 8px; 327 font-size: 20px; 328 } 329 330 .text-container { 331 margin: 20px 8px; 332 font-size: 20px; 333 border-radius: 5px; 334 background: linear-gradient(to right, rgb(112, 158, 242), rgb(255, 255, 255)); 335 color: white; 336 } 337 338 .drag-box .label-text-container { 339 color: rgba(190, 190, 190, 0.8); 340 transition: all linear 0.1s; 341 } 342 343 .icon-container { 344 margin: 15px; 345 } 346 347 .fa-file { 348 color: rgba(247, 187, 219, 0.8); 349 font-size: 100px; 350 transition: all linear 0.1s; 351 } 352 353 /* 当进入文件的时候添加css */ 354 .drag-box:hover { 355 border: 5px dashed rgba(112, 155, 248, 1); 356 } 357 358 .drag-box:hover .fa-file { 359 color: rgb(245, 124, 188); 360 } 361 362 .drag-box:hover .label-text-container { 363 color: rgb(68, 68, 68); 364 } 365 366 367 368 /* 当拖动文件的时候添加css */ 369 .draging-drag-box { 370 border: 5px dashed rgba(112, 155, 248, 1); 371 } 372 373 .draging-fa-file { 374 color: rgb(245, 124, 188); 375 } 376 377 .draging-label-text-container { 378 color: rgb(68, 68, 68); 379 } 380 381 /* 点击上传文件的时候的那个input */ 382 label input { 383 display: none; 384 } 385 386 387 .review { 388 border: 1px solid transparent; 389 border-radius: 5px; 390 color: #777; 391 display: flex; 392 font-size: 12px; 393 align-items: center; 394 padding: 10px; 395 margin: 5px 8px; 396 } 397 398 .review:hover { 399 cursor: pointer; 400 /* border: 1px solid #ddd; */ 401 box-shadow: 0 3px 10px -5px rgba(0, 0, 0, 0.7); 402 } 403 404 .pre-upload-bar { 405 margin: 10px 10px; 406 height: 20px; 407 } 408 409 .pre-upload-bar span { 410 font-size: 12px; 411 font-weight: 20px; 412 color: #777 413 } 414 415 .pre-upload-bar-done { 416 background: linear-gradient(to left, rgb(112, 158, 242), rgb(119, 140, 255)); 417 box-shadow: 0 3px 3px -5px rgb(100, 115, 143), rgb(134, 138, 165); 418 border-radius: 5px; 419 height: 3px; 420 width: 0; 421 transition: width ease 0.2s; 422 } 423 424 .review-file-name-container { 425 width: 100px; 426 } 427 428 .review-image-container { 429 margin: 0 8px 0 0; 430 } 431 432 .review-image { 433 width: 50px; 434 } 435 436 .pre-upload-list { 437 list-style: none; 438 /* 取消缩进 */ 439 margin: 0px; 440 padding: 0px 441 } 442 443 .file-name { 444 width: 100%; 445 float: left; 446 overflow: hidden; 447 text-overflow: ellipsis; 448 white-space: normal; 449 } 450 451 .progress { 452 background-color: rgba(100, 100, 100, 0.2); 453 border-radius: 5px; 454 position: relative; 455 margin: 0 10px; 456 height: 10px; 457 width: 150px; 458 } 459 460 .progress-done { 461 background: linear-gradient(to left, rgb(242, 112, 156), rgb(255, 148, 114)); 462 box-shadow: 0 3px 3px -5px rgb(242, 112, 156), 0 2px 5px rgb(242, 112, 156); 463 border-radius: 5px; 464 height: 10px; 465 width: 0; 466 transition: width ease 0.1s; 467 } 468 469 .select-box { 470 width: 20px; 471 height: 20px; 472 margin: 0 0 0 36px; 473 } 474 475 476 /* list的transition group */ 477 .list-enter, 478 .list-leave-to { 479 opacity: 0; 480 } 481 482 .list-enter-active { 483 animation: moveIn 1s; 484 } 485 486 .list-leave-active { 487 animation: moveOut 1s; 488 /* transition: all 1s linear; */ 489 } 490 491 @keyframes moveIn { 492 0% { 493 opacity: 0; 494 transform: translate(30px, 15px); 495 } 496 497 30% { 498 opacity: 0.5; 499 transform: translate(0px, 15px); 500 } 501 502 100% { 503 opacity: 1; 504 transform: translate(0, 0px); 505 } 506 } 507 508 @keyframes moveOut { 509 0% { 510 opacity: 1; 511 transform: translate(0, 0px); 512 } 513 514 30% { 515 opacity: 0.5; 516 transform: translate(0px, 15px); 517 } 518 519 100% { 520 opacity: 0; 521 transform: translate(30px, 15px); 522 } 523 } 524 525 526 .bottom-select { 527 margin: 5px 8px; 528 padding: 0 10px; 529 height: 40px; 530 } 531 532 .bottom-select .bottom-select-button { 533 cursor: pointer; 534 color: white; 535 margin: 5px; 536 padding: 7px; 537 float: right; 538 transition: all linear 0.1s; 539 background-color: rgb(247, 159, 172); 540 border-radius: 5px; 541 } 542 543 .bottom-select-info span { 544 font-size: 15px; 545 font-weight: 200; 546 } 547 548 .bottom-select-info .span-special { 549 font-weight: 1000; 550 } 551 552 .bottom-upload { 553 margin: 50px auto 10px auto; 554 width: 80px; 555 height: 40px; 556 text-align: center; 557 padding: 5px; 558 border-radius: 5px; 559 background-color: lightpink; 560 color: white; 561 } 562 .bottom-upload span{ 563 letter-spacing:5px; 564 margin: auto; 565 font-size: 30px; 566 } 567 </style> 568 569 </html>
总结
明天继续写
写完把详细过程记录一下
Let it roll