当前位置: 首页 > article >正文

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

<template>
  <div class="zh-upload">
    <div class="zh-upload-button" @click="upload">
      <slot></slot>
    </div>
    <div><slot name="tip"></slot></div>
    <input ref="file" type="file" :accept="accept" :multiple="multiple" @change="changeFile">
    <ul>
      <li v-for="file in files">
        {{file.name}}
        <zh-progress v-if="file.status==='uploading'" :percent="file.percent"></zh-progress>
      </li>
    </ul>
  </div>
</template>

<script>
import _ from 'lodash'
import {ajax} from './upload'
export default {
  name:'zh-upload',
  props:{
    name:{
      type:String,
      default:'file'
    },
    action:{
      type:String,
      default:''
    },
    accept:{
      type:String,
      default:''
    },
    multiple:{
      type:Boolean,
      default:false
    },
    limit:{
      type:Number,
      default:0
    },
    onExceed:{
      type:Function,
    },
    beforeUpload:{
      type:Function,
    },
    httpRequest:{
      type:Function,
      default:ajax,
    },
    fileList:{
      type:Array,
      default:[]
    }
  },
  data(){
    return {
      files:[],
      uniqueId:1,
    }
  },
  watch:{
    fileList:{
      deep:true,
      immediate:true,
      handler(val){
        this.files=val.map(item=>{
          item.uid=`${+new Date}${this.uniqueId++}`
          item.status='success'
          return item;
          // const file={
          //   uid:item.uid,
          //   name:item.name,
          //   url:item.url,
          //   status:'success', // 完成成功态时只关心 name & url
          //   percent:0,
          // }
          // return file;
        })
      }
    }
  },
  methods:{
    upload(){
      this.$refs.file.value=''
      this.$refs.file.click()
    },
    changeFile(ev){
      let files=ev.target.files;
      // 限制最多上传的文件数
      if(this.limit && this.files.length+files.length>this.limit){
        return this.onExceed();
      }
      // [...files].forEach
      _.forEach(files,rawFile=>{
        this.uploadStart(rawFile)
        this.uploadFile(rawFile)
      })
    },
    uploadStart(rawFile){
      rawFile.uid=`${+new Date}${this.uniqueId++}`
      // 构造新的文件对象
      const fileNew={
        uid:rawFile.uid,
        name:rawFile.name,
        size:rawFile.size,
        type:rawFile.type,
        status:'uploadstart',
        percent:0,
        rawFile,
      }
      this.files.push(fileNew)

    },
    uploadFile(rawFile){
      // @todo beforeUpload
      if(typeof this.beforeUpload === 'function'){
        let flag=this.beforeUpload(rawFile) // 目前没考虑promise的情况
        if(!flag) return
      }
      this.post(rawFile)
    },
    post(rawFile){
      const options={
        filename:this.name,
        file:rawFile,
        action:this.action,
        onSuccess:(res)=>{
          this.handleSuccess(res,rawFile)

        },
        onError:(res)=>{

        },
        onProgress:(ev)=>{
          this.handleProgress(ev,rawFile)
        },
      }
      this.httpRequest(options)
    },
    handleSuccess(res,rawFile){
      const file=this.files.find(f=>f.uid===rawFile.uid)
      file.status='success'
    },
    handleProgress(ev,rawFile){
      // file是原生file文件,找到files中对应的file对象
      const file=this.files.find(f=>f.uid===rawFile.uid)
      file.status='uploading'
      file.percent=Math.round(ev.loaded/ev.total*100)

    }
  }
}
</script>

<style scoped lang="scss">
.zh-upload{
  &-button{
    display: inline-block;
  }
  input[type=file]{
    display: none;
  }
}
</style>

upload.js

export function ajax(options){
    let xhr=new XMLHttpRequest()
    const {filename,file,action,onSuccess,onError,onProgress}=options;
    const fd=new FormData
    fd.append(filename,file)
    xhr.open('post',action)
    xhr.onload=()=>{
        onSuccess(JSON.parse(xhr.responseText))
    }
    xhr.onerror=()=>{
        onError(JSON.parse(xhr.errorText))
    }
    xhr.upload.onprogress=(ev)=>{
        onProgress(ev)
    }
    xhr.send(fd)
    return xhr;
}

progress.vue

<template>
<div class="progress-outer" :style="outerStyle">
  <div class="progress-inner" :style="innerStyle"></div>
</div>
</template>

<script>
export default {
  name:'zh-progress',
  props:{
    strokeWidth:{
      type:Number,
      default:10
    },
    strokeColor:{
      type:String,
      default:'blue'
    },
    percent:{
      type:Number,
      default:0
    }
  },
  computed:{
    outerStyle(){
      return {
        height:`${this.strokeWidth}px`,
      }
    },
    innerStyle(){
      return {
        width:`${this.percent}%`,
        background:this.strokeColor
      }
    }
  },
  watch:{
    percent(val){
      console.log(val,'percent');
    }
  }
}
</script>

<style scoped lang="scss">
.progress-outer{
  width: 100%;
  background: grey;
  position: relative;
  .progress-inner{
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    transition:width .3s ease;
  }
}
.progress-outer,.progress-inner{
  border-radius: 5px;
}
</style>

设计组件思想:

用户要有那些功能

暴露用户那些功能

用户有哪些行为

拖拽上传

主要就是onDrop事件

ondragover.prevent ondragleave.prevent

Popover组件

appendChild insertBefore都会对dom有移动性

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

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


http://www.kler.cn/news/106912.html

相关文章:

  • 框架安全-CVE 复现SpringStrutsLaravelThinkPHP漏洞复现
  • Peter算法小课堂—归并排序
  • 【Linux】安装与配置虚拟机及虚拟机服务器坏境配置与连接
  • LibreOffice编辑excel文档如何在单元格中输入手动换行符
  • 如何中断一个正在运行的线程?
  • Java关于实例对象调用静态变量和静态方法问题
  • ue5 右击.uproject generator vs project file 错误
  • VM虚拟机的安装与配置及操作系统的安装
  • [RISC-V]verilog
  • DeepSpeed: 大模型训练框架 | 京东云技术团队
  • 【DOCKER】
  • 一个简单的注册页面,如有错误请指正(2.css)
  • “穷”用英语怎么说?柯桥成人英语培训
  • 数据结构与算法之排序: 归并排序 (Javascript版)
  • Jenkins入门级安装部署
  • 轻量封装WebGPU渲染系统示例<1>-彩色三角形(源码)
  • MySQL存储过程与函数
  • SOLIDWORKS® 2024 新功能 - SIMULATION
  • 人生岁月年华
  • Pytorch - 数据增广
  • Unity3D 如何用unity引擎然后用c#语言搭建自己的服务器
  • C# 基于腾讯云人脸核身和百度云证件识别技术相结合的 API 实现
  • ​ iOS自动混淆测试处理笔记
  • 干式电抗器的尺寸和重量对系统有什么影响?
  • Redis快速上手篇八(redission分布式锁)
  • AXI-Stream协议详解(3)—— AXI4-Stream IP核原理分析
  • 使用一个Series序列减去另一个Series序列Series.subtract()
  • buuctf_练[GYCTF2020]FlaskApp
  • UVa10976 Fractions Again?!(分数拆分)
  • shell实验