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>

总结

  明天继续写

  写完把详细过程记录一下

posted @ 2021-02-16 23:10  WaterMealone  阅读(288)  评论(0编辑  收藏  举报