美文网首页vue
VUE3(二十七)自定义upload上传组件(显示上传进度)

VUE3(二十七)自定义upload上传组件(显示上传进度)

作者: camellias__ | 来源:发表于2021-04-26 09:07 被阅读0次

    项目中需要使用到文件上传。我这里自己定义了一个上传文件的组件

    支持显示上传进度显示(我这里显示的是真实的上传进度,当然,这个可以根据你自己的需求修改)。

    支持多文件上传。

    最终效果如下:

    20210422091935790.gif

    代码:

    Uploads.vue

    <template>
      <div class="myUpload">
        <!-- 上传文件列表 -->
        <div class="myUpload-img center" v-for="(item,index) in mydata" :key="index">
          <img :src="item.url" v-if="type=='image'" />
          <div class="fileLogo" v-else>
            {{item.ext}}
          </div>
          <!-- 删除文件 -->
          <div class="delete" @click="del(item)">
            <i class="icon-delete">+</i>
          </div>
        </div>
        <!-- 上传框 -->
        <label class="btn center" v-if="(limit == 1 && mydata.length < 1) || limit > 1">
          <i class="icon-add">+</i>
          <!-- 多图 -->
          <input type="file"  v-if="multiple == 1 " multiple  class="inputfile" @change="handlerUpload($event)" :accept="accept" />
          <!-- 单图 -->
          <input type="file"  v-else  class="inputfile" @change="handlerUpload($event)" :accept="accept" />
        </label>
      </div>
    </template>
     
    <style scoped>
      @import "../../assets/css/components/pc/Uploads.scss";
    </style>
     
    <script>
      // 引入js文件
      import Uploads from "/@/assets/js/components/pc/Uploads";
      // 使用js对象
      export default {
        ...Uploads,
      };
    </script>
    

    Uploads.ts

    // 引入路由
    import { useRouter, useRoute } from "vue-router";
    import {
      PropType,
      ref,
      watch,
      reactive,
      toRefs,
      inject,
      provide
    } from "vue";
    import { common, userinfo } from "/@/hooks/common.ts";
    // 引入公共js文件
    import utils from "/@/assets/js/public/function";
    // 引入axios钩子
    import axios from "/@/hooks/axios.ts";
     
    export default {
      name: "Uploads",
      /**
       * @name: 父组件传递来的参数
       * @author: camellia
       * @email: guanchao_gc@qq.com
       * @date: 2021-01-10
       */
      props: {
        // 多文件上传(0:单文件上传,1:多文件上传)
        multiple:{
          type: Number,
          default: 0, 
        },
        // 上传数量
        limit:{
          type: Number,
          default: 0, 
        },
        // 上传地址 url
        action:{
          type: String,
          default: '', 
        },
        // 文件类型
        ext:{
          type: Array,// 数组类型
          default: [".gif", ".jpeg", ".jpg",".png",".bmp",".doc",".docx",".xls",".mp4",".rmvb",".zip"], 
        },
        // 文件大小(mb)
        size:{
          type: Number,
          default: 0, 
        },
        // 列表初始值
        data:{
          type: Array,// 数组类型
          default: [],
        },
        // 上传文件类型(image | file)
        type:{
          type: String,
          default: 'image', 
        },
        // 随机名(1或者0)
        autoName:{
          type: Boolean,
          default: 1,
        }
      },
      // VUE3语法 setup函数
      // setup官方文档:https://www.vue3js.cn/docs/zh/guide/composition-api-setup.html#参数
      setup(props: any, content: any)
      {
        const router = useRouter();
        /**
         * @name: 声明data
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-01-10 
         */
        const data = reactive({
          mydata: props.data ? props.data.slice() : [],
          accept: props.ext,
        });
     
        /**
         * @name: 整理目前已有文件
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-02-20 
         * @param:  file  object  文件对象
         * @param:  obj object  文件上传成功之后返回的信息对象
         */
        const isImg = (file:any, obj:any) => {
          if (props.type == "image") 
          {
            let fileReader = new FileReader();
            fileReader.readAsDataURL(file);
            fileReader.onload = function (ev:any) {
              // 这是base64文件编码
              // obj.url = ev.target.result;
              if(props.limit == 1)
              {
                data.mydata = [];
              }
              data.mydata.push(obj);
            };
          } 
          else 
          {
            if (props.limit == 1) 
            {
              data.mydata = [];
            }
            data.mydata.push(obj);
          }
        };
     
        /**
         * @name: 删除文件
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-02-20 
         * @param:  item  object  文件信息
         */
        const del = (item:any) => {
          data.mydata = data.mydata.filter(function (obj:any) {
            return obj != item;
          });
        };
     
        /**
         * @name: 组装上传数据(可多文件上传)
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-02-20 
         * @param:  e obj 文件流
         */
        const handlerUpload = (e:any) => {
          var file = '';
          // 判断文件上传数量是否超限
          if (data.mydata.length >= props.limit) 
          {
            utils.alertMsg(2000, '上传文件数量已达到上限!'); return;
          }
          for (var i = 0; i < e.target.files.length; i++)
          {
            // 判断文件上传数量是否超限
            if (data.mydata.length >= props.limit) 
            {
              utils.alertMsg(2000, '上传文件数量已达到上限!'); return;
            }
            file = e.target.files[i];
            // 上传文件信息
            let dataObj = {
              file: file,
              ext: data.accept,
              size: props.size,
              autoName: props.autoName == 0 ? props.autoName : 1
            };
            // 调用上传方法
            postUpload(dataObj)
              .then(function (res: any) {
                let obj = res.data;
                isImg(file, obj);
                utils.alertMsg(2000, '操作成功!'); return;
              })
              .catch(function (error: any) {
                console.log(error);
                utils.alertMsg(2000, error.data.msg); return;
              });
          }
        };
     
        /**
         * @name: 上传接口
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-02-18 
         * @param:  data  object  上传文件数据对象
         */
        const postUpload = (data:any) => {
          var obj = new FormData();
          for (let item in data) 
          {
            obj.append(item, data[item]);
          }
          let config = {
            headers: {
              "Content-Type": "multipart/form-data"
            },
            onUploadProgress: (e:any) => {
              var completeProgress = ((e.loaded / e.total) * 100) | 0;
              // props.progress = completeProgress; //上传过程
                // 关闭 上传进度显示
              utils.alertLoadExec(false);
              utils.alertLoadExec(true, '上传进度:'+completeProgress+'%');
            }
          };
          return new Promise(function (resolve, reject) {
            axios
              .post(props.action, obj, config)
              .then(function (res) {
                // 关闭 上传进度显示
                utils.alertLoadExec(false);
                if (res.data.code == 1) 
                {
                  resolve(res);
                }
                else 
                {
                  reject(res);
                }
              })
              .catch(function (error) {
                reject(error);
                // 关闭 上传进度显示
                utils.alertLoadExec(false);
              });
          });
        }
     
        /**
          * @name: 将data绑定值dataRef
          * @author: camellia
          * @email: guanchao_gc@qq.com
          * @date: 2021-01-10 
          */
        const dataRef = toRefs(data);
        return {
          isImg, handlerUpload, postUpload, del,
          ...dataRef
        }
     
      }
     
    };
    

    Uploads.scss

      i {
        font-style: normal;
      }
     
      .myUpload {
        display: flex;
      }
     
      .inputfile {
        width: 0px;
        height: 0px;
        opacity: 0;
        overflow: hidden;
        position: absolute;
        z-index: -1;
      }
     
      .btn {
        width: 200px;
        height: 200px;
        border-radius: 4px;
        font-size: 3rem;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        border: 1px dashed rgb(107 60 60);
        color: rgb(72 41 41);
      }
     
      .btn:hover {
        color: #6bc7ff;
        border-color: #6bc7ff;
      }
     
      .myUpload-img {
        width: 200px;
        height: 200px;
        margin-right: 10px;
        position: relative;
        border-radius: 4px;
        border: 1px dashed#ccc;
      }
     
      .myUpload-img:hover .delete {
        display: flex;
      }
     
      .myUpload-img:hover {
        border-color: red;
      }
     
      .myUpload-img img {
        width: 100%;
        height: 100%;
      }
     
      .myUpload-img .fileLogo {
        color: #adadad;
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        position: absolute;
        top: 0;
        bottom: 0;
        text-transform: uppercase;
        font-size: 3rem;
      }
     
      .myUpload-img .delete {
        width: 100%;
        height: 100%;
        border-radius: 4px;
        position: absolute;
        background: rgba(0, 0, 0, 0.4);
        top: 0;
        bottom: 0;
        display: none;
        align-items: center;
        justify-content: center;
        cursor: pointer;
      }
     
      .icon-delete {
        color: red;
        font-size: 3rem;
        transform: rotate(45deg);
      }
      .center{
        margin:auto;
      }
    

    上传进度弹窗代码:

    utils
    .
    alertMsg
    

    请移步《VUE3(二十四)自定义alert弹窗组件

    调用实例:父组件传入子组件的参数,我在子组件ts文件中都有注释。

    <Uploads class="upload" :limit="1" :type="'image'" :ext="ext" :data="userLogoInfo"
                  :action="'后端上传地址'" :autoName="1" :size="5*1024*1024" :multiple="0">
                </Uploads>
    

    以上大概是我自定义上传组件的全部代码。

    有好的建议,请在下方输入你的评论。

    欢迎访问个人博客
    https://guanchao.site

    相关文章

      网友评论

        本文标题:VUE3(二十七)自定义upload上传组件(显示上传进度)

        本文链接:https://www.haomeiwen.com/subject/lnusrltx.html