• vue2组件库-上传组件


    vue2组件库

    上传组件

    核心思路:监控整个上传的流程

    上传成功 上传失败

    类型:拖拽 多个文件上传

    上传必备属性 & 钩子属性

    跟上传强关联的属性,上传必备的字段

    name: 提交的那个formData字段名

    action:ajax接口路径

    limit:限制提交个数

    钩子函数

    上传fileList数据构造

    dom: this.$refs

    选中文件 上传

    按照整个上传的流程

    fileList中每个对象的状态

    1. 刚放进去,准备好了待上传
    2. 上传中
    3. 上传完成

    自己创建的一个文件对象

    数据层fileList

    弄一个数据同步v-model或.async,我就给你一个数据不希望它有什么同步的功能,我自己身上有一份数据,用户的数据也格式化放到这个数组里不涉及什么子改父父改子,自己处理自己的数据。

    文件变化了,触发文件变化的钩子。

    发起ajax上传请求

    httpPost的处理

    处理上传前+上传中+上传成功的各状态展示

    file.status percent 

    onProgress onSuccess onError

    upload.vue

    1. <template>
    2.   <div class="zh-upload">
    3.     <div class="zh-upload-button" @click="upload">
    4.       <slot></slot>
    5.     </div>
    6.     <div><slot name="tip"></slot></div>
    7.     <input ref="file" type="file" :accept="accept" :multiple="multiple" @change="changeFile">
    8.     <ul>
    9.       <li v-for="file in files">
    10.         {{file.name}}
    11.         <zh-progress v-if="file.status==='uploading'" :percent="file.percent"></zh-progress>
    12.       </li>
    13.     </ul>
    14.   </div>
    15. </template>
    16. <script>
    17. import _ from 'lodash'
    18. import {ajax} from './upload'
    19. export default {
    20.   name:'zh-upload',
    21.   props:{
    22.     name:{
    23.       type:String,
    24.       default:'file'
    25.     },
    26.     action:{
    27.       type:String,
    28.       default:''
    29.     },
    30.     accept:{
    31.       type:String,
    32.       default:''
    33.     },
    34.     multiple:{
    35.       type:Boolean,
    36.       default:false
    37.     },
    38.     limit:{
    39.       type:Number,
    40.       default:0
    41.     },
    42.     onExceed:{
    43.       type:Function,
    44.     },
    45.     beforeUpload:{
    46.       type:Function,
    47.     },
    48.     httpRequest:{
    49.       type:Function,
    50.       default:ajax,
    51.     },
    52.     fileList:{
    53.       type:Array,
    54.       default:[]
    55.     }
    56.   },
    57.   data(){
    58.     return {
    59.       files:[],
    60.       uniqueId:1,
    61.     }
    62.   },
    63.   watch:{
    64.     fileList:{
    65.       deep:true,
    66.       immediate:true,
    67.       handler(val){
    68.         this.files=val.map(item=>{
    69.           item.uid=`${+new Date}${this.uniqueId++}`
    70.           item.status='success'
    71.           return item;
    72.           // const file={
    73.           //   uid:item.uid,
    74.           //   name:item.name,
    75.           //   url:item.url,
    76.           //   status:'success'// 完成成功态时只关心 name & url
    77.           //   percent:0,
    78.           // }
    79.           // return file;
    80.         })
    81.       }
    82.     }
    83.   },
    84.   methods:{
    85.     upload(){
    86.       this.$refs.file.value=''
    87.       this.$refs.file.click()
    88.     },
    89.     changeFile(ev){
    90.       let files=ev.target.files;
    91.       // 限制最多上传的文件数
    92.       if(this.limit && this.files.length+files.length>this.limit){
    93.         return this.onExceed();
    94.       }
    95.       // [...files].forEach
    96.       _.forEach(files,rawFile=>{
    97.         this.uploadStart(rawFile)
    98.         this.uploadFile(rawFile)
    99.       })
    100.     },
    101.     uploadStart(rawFile){
    102.       rawFile.uid=`${+new Date}${this.uniqueId++}`
    103.       // 构造新的文件对象
    104.       const fileNew={
    105.         uid:rawFile.uid,
    106.         name:rawFile.name,
    107.         size:rawFile.size,
    108.         type:rawFile.type,
    109.         status:'uploadstart',
    110.         percent:0,
    111.         rawFile,
    112.       }
    113.       this.files.push(fileNew)
    114.     },
    115.     uploadFile(rawFile){
    116.       // @todo beforeUpload
    117.       if(typeof this.beforeUpload === 'function'){
    118.         let flag=this.beforeUpload(rawFile) // 目前没考虑promise的情况
    119.         if(!flag) return
    120.       }
    121.       this.post(rawFile)
    122.     },
    123.     post(rawFile){
    124.       const options={
    125.         filename:this.name,
    126.         file:rawFile,
    127.         action:this.action,
    128.         onSuccess:(res)=>{
    129.           this.handleSuccess(res,rawFile)
    130.         },
    131.         onError:(res)=>{
    132.         },
    133.         onProgress:(ev)=>{
    134.           this.handleProgress(ev,rawFile)
    135.         },
    136.       }
    137.       this.httpRequest(options)
    138.     },
    139.     handleSuccess(res,rawFile){
    140.       const file=this.files.find(f=>f.uid===rawFile.uid)
    141.       file.status='success'
    142.     },
    143.     handleProgress(ev,rawFile){
    144.       // file是原生file文件,找到files中对应的file对象
    145.       const file=this.files.find(f=>f.uid===rawFile.uid)
    146.       file.status='uploading'
    147.       file.percent=Math.round(ev.loaded/ev.total*100)
    148.     }
    149.   }
    150. }
    151. </script>
    152. <style scoped lang="scss">
    153. .zh-upload{
    154.   &-button{
    155.     display: inline-block;
    156.   }
    157.   input[type=file]{
    158.     display: none;
    159.   }
    160. }
    161. </style>

    upload.js

    1. export function ajax(options){
    2.     let xhr=new XMLHttpRequest()
    3.     const {filename,file,action,onSuccess,onError,onProgress}=options;
    4.     const fd=new FormData
    5.     fd.append(filename,file)
    6.     xhr.open('post',action)
    7.     xhr.onload=()=>{
    8.         onSuccess(JSON.parse(xhr.responseText))
    9.     }
    10.     xhr.onerror=()=>{
    11.         onError(JSON.parse(xhr.errorText))
    12.     }
    13.     xhr.upload.onprogress=(ev)=>{
    14.         onProgress(ev)
    15.     }
    16.     xhr.send(fd)
    17.     return xhr;
    18. }

    progress.vue

    1. <template>
    2. <div class="progress-outer" :style="outerStyle">
    3.   <div class="progress-inner" :style="innerStyle"></div>
    4. </div>
    5. </template>
    6. <script>
    7. export default {
    8.   name:'zh-progress',
    9.   props:{
    10.     strokeWidth:{
    11.       type:Number,
    12.       default:10
    13.     },
    14.     strokeColor:{
    15.       type:String,
    16.       default:'blue'
    17.     },
    18.     percent:{
    19.       type:Number,
    20.       default:0
    21.     }
    22.   },
    23.   computed:{
    24.     outerStyle(){
    25.       return {
    26.         height:`${this.strokeWidth}px`,
    27.       }
    28.     },
    29.     innerStyle(){
    30.       return {
    31.         width:`${this.percent}%`,
    32.         background:this.strokeColor
    33.       }
    34.     }
    35.   },
    36.   watch:{
    37.     percent(val){
    38.       console.log(val,'percent');
    39.     }
    40.   }
    41. }
    42. </script>
    43. <style scoped lang="scss">
    44. .progress-outer{
    45.   width: 100%;
    46.   background: grey;
    47.   position: relative;
    48.   .progress-inner{
    49.     position: absolute;
    50.     left0;
    51.     top0;
    52.     height: 100%;
    53.     transition:width .3s ease;
    54.   }
    55. }
    56. .progress-outer,.progress-inner{
    57.   border-radius: 5px;
    58. }
    59. </style>

    设计组件思想:

    用户要有那些功能

    暴露用户那些功能

    用户有哪些行为

    拖拽上传

    主要就是onDrop事件

    ondragover.prevent ondragleave.prevent

    Popover组件

    appendChild insertBefore都会对dom有移动性

    事件:事件机制谁在谁里面,怎么触发这个事件,事件都有哪些问题

    具体位置:用js算left top的值

  • 相关阅读:
    【OpenCV(3)】linux arm aarch 是 opencv 交叉编译与使用
    差分约束——区间
    记录Windows安装Tomcat后无法打印项目日志原因,非catalina日志
    linux进程间通信之管道通信
    【华为机试真题 Python】按身高和体重排队
    如何在多线程异步的情况下保证事务?
    Biotinyl-εAhx-Amyloid β-Protein (1-42),CAS: 1872440-40-8
    CMake Day 7 —— option
    【深度学习】基于tensorflow的服装图像分类训练(数据集:Fashion-MNIST)
    信息学奥赛一本通题解目录(没写完)
  • 原文地址:https://blog.csdn.net/betterangela/article/details/134088036