vue中上传组件封装及使用

1.from中引用

 <el-form-item label="打卡照片" prop="checkInPhoto">
          <myFile :uploadPm="uploadPm" ref="file1Ref" @notice="_getFileIds"/><br>
        </el-form-item>

2.在data中定义 uploadPm

 uploadPm: {
        fieldCode: "dkzp",//打卡照片
        attachmentType: "PICTURE",//只有为"PICTURE"才使用照片墙这个会被存入附件表所以必须传
        fileType: ['png', 'jpg','mp4'],//允许上传的格式
        limit: 5,//上传图片的最大个数
        isRead: false,//是否只读(编辑时候传true)
        fileSize: 100 //单个图片的最大大小限制
      },

3.在methods中定方法

 _getFileIds: function (data) {
      this.form.fileIds = data;
    },

4.在新增方法中

 this.$nextTick(() => {
        _that.$refs.file1Ref.cleanFiles();
        _that.$refs.file1Ref.setIsRead(false);
      });

5.修改方法中

 this.$nextTick(() => {
          _that.$refs.file1Ref.showFiles(response.data.id);
          _that.$refs.file1Ref.setIsRead(false);
        });

6.查看方法中

 this.$nextTick(() => {
          _that.$refs.file1Ref.showFiles(response.data.id);
          _that.$refs.file1Ref.setIsRead(true);
        });

下面代码为上传组件封装

<template>
  <div class="upload-file">

    <el-upload
      :class="{hide:uploadPm.isRead}"
      v-if="isPic"
      :disabled="isRead"
      list-type="picture-card"
      :action="uploadFileUrl"
      :before-upload="handleBeforeUpload"
      :file-list="fileList"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      :on-success="handleUploadSuccess"
      :on-preview="handlePictureCardPreview"
      :on-remove="handleRemove"
      :before-remove="beforeRemove"
      :headers="headers"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog id="imgView" style="left: 100px" :visible.sync="dialogVisible" :width="dialogWidth?dialogWidth+'px':''" :height="dialogHeight?dialogHeight+'px':''"  :modal="false" >
      <img :width="imgWidth?imgWidth:'50%'" :height="imageHeight?imageHeight:''" :src="dialogImageUrl" alt="" style="display: block; margin: 0 auto;">
      <div slot="footer" class="dialog-footer">
        <el-button icon="el-icon-close" class="qzlbg" size="small"  @click="dialogVisible = false" style="margin: 30px 45%;">取 消</el-button>
      </div>
    </el-dialog>

    <el-upload
      v-if="!isPic"
      :disabled="isRead"
      :action="uploadFileUrl"
      :before-upload="handleBeforeUpload"
      :file-list="fileList"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      :on-success="handleUploadSuccess"
      :show-file-list="false"
      :headers="headers"
      class="upload-file-uploader"
      ref="upload"
    >
      <!-- 上传按钮 -->
      <el-button size="mini" type="primary" class="blueLinearbg">选取文件</el-button>
      <!-- 上传提示 -->
      <div class="el-upload__tip" slot="tip" v-if="showTip">
        请上传
        <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template>
        <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>
        的文件
      </div>
    </el-upload>

    <!-- 文件列表 -->
    <transition-group v-if="!isPic" class="upload-file-list el-upload-list el-upload-list--text"
                      name="el-fade-in-linear" tag="ul">
      <div class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList"
           v-bind:key="file.name">
        <el-link :href="file.url" :underline="false" target="_blank">
          <span class="el-icon-document"> {{ file.fileName }} </span>
        </el-link>
        <div class="ele-upload-list__item-content-action" v-if="!uploadPm.isRead">
          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
        </div>
      </div>
    </transition-group>

    <!--視頻查看-->
    <el-dialog
      z-index="99999"
      title="视频预览"
      :visible.sync="dialogPlay"
      width="30%"
      :modal="false"
      @close="closeDialog"
    >
      <video
        :src="videoUrl"
        controls
        autoplay
        class="video"
        ref="dialogVideo"
        width="100%"
      />
    </el-dialog>
  </div>


</template>

<script>
  import {getToken} from "@/utils/auth";
  import request from '@/utils/request'

  export default {
    name: "lengFileUploadPlus",
    props: {
      //父页面传过来的附件上传相关参数
      uploadPm: {
        type: [Object]
      },
      value: [String, Object, Array],
      // 是否显示提示
      isShowTip: {
        type: Boolean,
        default: true
      }
    },
    data() {
      return {
        loading:null,
        waitRemove:false,//等待删除忽略删除提示
        clientWidth:null,
        clientHeight:null,
        imgWidth:null,
        imageHeight:null,
        dialogWidth:null,
        dialogHeight:null,
        videoUrl:"",
        dialogPlay:false,

        //放大图片的路径
        dialogImageUrl: '',
        //放大器展示开关
        dialogVisible: false,
        // disabled: false,
        //展示照片墙还是列表true展示照片墙
        isPic: true,
        //是否允许编辑
        isRead: {
          type: Boolean,
          default: false
        },
        // 数量限制
        limit: {
          type: Number,
          default: 5
        },
        //单个文件最大值单位MB
        fileSize: {
          type: Number,
          default: 20
        },
        //允许上传的文件类型
        fileType: {
          type: Array,
          default: () => ["doc", "xls", "ppt", "txt", "pdf", 'png', 'jpg', 'mp4', 'zip'],
        },
        uploadFileUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
        headers: {
          Authorization: "Bearer " + getToken(),
          FieldCode:this.uploadPm.fieldCode,
        },
        fileList: [],//存放附件的列表
        ids: [],//附件的id用来修改entityId
      };
    },
    watch: {
      value: {
        handler(val) {
          if (val) {
            let temp = 1;
            // 首先将值转为数组
            const list = Array.isArray(val) ? val : this.value.split(',');
            // 然后将数组转为对象数组
            this.fileList = list.map(item => {
              if (typeof item === "string") {
                item = {name: item, url: item};
              }
              item.uid = item.uid || new Date().getTime() + temp++;
              return item;
            });
          } else {
            this.fileList = [];
            return [];
          }
        },
        deep: true,
        immediate: true
      }
    },
    created() {
      //初始化父页面传来的上传参数
      this.init();
    },
    computed: {
      // 是否显示提示
      showTip() {
        return this.isShowTip && (this.fileType || this.fileSize);
      },
    },
    methods: {
      beforeRemove(){
        if(this.waitRemove){
          this.waitRemove = false;
          return true;
        }
        const p = new Promise((resolve, reject) => {
          this.$confirm('此操作将删除该文件, 是否继续?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
          })
            .then(() => {
              console.log("beforeRemove-then")
              this.rmVModel();
              resolve(true)
            })
            .catch(() => {
              console.log("beforeRemove-catch")
              this.rmVModel();
              reject(false)
            })
        })
        return p;
        /*return  this.$confirm('此操作将删除该文件, 是否继续?', '提示', {
           confirmButtonText: '确定',
           cancelButtonText: '取消',
           type: 'warning',
         })
           .then(() => {
             console.log("beforeRemove-then")
             $(".v-modal").remove();
            this.Promise.resolve(true)
           })
           .catch(() => {
             console.log("beforeRemove-catch")
             $(".v-modal").remove();
             this.Promise.resolve(false)
           });*/
      },
      rmVModel(){
        // $(".v-modal").remove();
        var elements = document.querySelectorAll('.v-modal');
        elements.forEach(function(element) {
          if (element.parentNode) {
            element.parentNode.removeChild(element);
          }
        });
      },
      closeDialog() {
        this.videoUrl = ""; //清空数据 关闭视频播放
        this.dialogPlay = false; //清空数据 关闭视频播放
      },
      handleRemove(file) {
        const findex = this.fileList.map(f => f.uid).indexOf(file.uid);
        if (findex > -1) {
          this.handleDelete(findex);
        }
      },
      handlePictureCardPreview(file) {
        console.log(file)
        //这里判断照片展示照片 视频展示视频
        if(this.getFileType(file.name) === "PICTURE"){
          this.showImg(file);
        }else if(this.getFileType(file.name) === "VIDEO"){
          this.showVideo(file);
        }
      },
      getFileType(fileName){
        // 定义图片格式的扩展名数组
        const pictureExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif', 'tiff', 'svg'];
        // 定义视频格式的扩展名数组
        const videoExtensions = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'];
        // 获取文件扩展名
        const extension = fileName.split('.').pop().toLowerCase();
        // 判断扩展名是否在图片格式数组中
        if (pictureExtensions.includes(extension)) {
          return 'PICTURE';
        }
        // 判断扩展名是否在视频格式数组中
        else if (videoExtensions.includes(extension)) {
          return 'VIDEO';
        }
        // 如果都不是,则返回'FILE'
        else {
          return 'FILE';
        }
      },
      showImg(file){
        this.clientWidth = document.body.clientWidth;
        this.clientHeight = document.body.clientHeight;
        this.dialogHeight = this.clientHeight*0.8;
        this.dialogWidth = this.clientWidth*0.8;
        let img = document.createElement('img');
        img.src=file.url;
        const self = this;
        img.onload = function(){
          self.imgWidth = img.width;
          self.imageHeight = img.height;
          self.setWH();
          self.dialogImageUrl = file.url;
          self.dialogVisible = true;
        }
      },
      //设置弹窗宽高和图片宽高
      setWH(){
        let bl = (this.imgWidth/this.dialogWidth >this.imageHeight/this.dialogHeight)?(this.dialogWidth*0.8/this.imgWidth):(this.dialogHeight*0.8/this.imageHeight);//放大或缩小比例
        this.imgWidth = this.imgWidth*bl;
        this.imageHeight = this.imageHeight*bl;

        /*
        if(this.imgWidth&&this.imageHeight&&(this.imgWidth>=this.dialogWidth*0.8||this.imageHeight>=this.dialogHeight*0.8)){
          this.imgWidth = this.imgWidth*0.95;
          this.imageHeight = this.imageHeight*0.95;
          this.setWH();
        }else if(this.imgWidth&&this.imageHeight&&(this.imgWidth<=this.dialogWidth*0.3||this.imageHeight<=this.dialogHeight*0.3)){
          this.imgWidth = this.imgWidth*1.1;
          this.imageHeight = this.imageHeight*1.1;
          this.setWH();
        }
        */
      },
      showVideo(o){
        this.dialogPlay = true;
        this.videoUrl = o.url;
      },
      //根据视频地址获取封面
      async getVideoBase64(url, second) {
        const video = document.createElement('video');
        video.setAttribute('crossOrigin', 'anonymous'); // 处理跨域
        video.setAttribute('src', url);
        // 静音操作,防止播放失败
        video.setAttribute('muted', 'muted');
        video.addEventListener('loadeddata', async () => {
          const canvas = document.createElement('canvas');
          const { width, height } = video; // canvas的尺寸和图片一样
          canvas.width = width;
          canvas.height = height;
          if (second) {
            video.currentTime = second;
            // 播放到当前时间的帧,才能截取到当前的画面
            await video.play();
            await video.pause();
          }
          canvas.getContext('2d')?.drawImage(video, 0, 0, width, height);
          return canvas.toDataURL('image/jpeg');
        });
      },




      handleDownload(file) {
        // console.log(file);
      },
      /*修改entityId*/
      upEntityId: function (entityId,callback) {
        //修改entityId
        let fileIds = this.getFileIds();
        // let attachmentType = this.uploadPm.attachmentType;
        updateEntityId(fileIds, entityId, this.uploadPm.attachmentType,function(){
          if(callback)
            callback();
        });
      },
      /*图片回显*/
      showFiles(entityId) {
        // console.log("showFiles  "+entityId)
        getFileList(entityId).then(res => {
          this.fileList = [];
          //填充fileList
          if (res) {
            for (let i in res) {
              this.fileList.push({
                name: res[i].url,
                url: res[i].url,
                attachmentType:res[i].attachmentType,
                attachmentId: res[i].id,
                fileName: res[i].fileName
              });
              console.log(this.fileList)
            }
          }
        })
      },
      /*图片回显*/
      showFilesByPm(entityId,entityName,fieldCode) {
        let parm = {};
        parm.entityId = entityId;
        parm.entityName = entityName;
        parm.fieldCode = fieldCode;
        getFileListByPm(parm).then(res => {
          this.fileList = [];
          //填充fileList
          if (res) {
            for (let i in res) {
              this.fileList.push({
                name: res[i].url,
                url: res[i].url,
                attachmentType:res[i].attachmentType,
                attachmentId: res[i].attachmentId,
                fileName: res[i].fileName
              });
              console.log(this.fileList)
            }
          }
        })
      },
      /*追加图片回显*/
      appendFiles(entityId) {
        // console.log("appendFiles  "+entityId)
        getFileList(entityId).then(res => {
          //填充fileList
          if (res) {
            for (let i in res) {
              if(res[i].url.indexOf('http://39.107.66.190:9300/files')>=0){
                const arr = res[i].url.split('http://39.107.66.190:9300/files');
                arr [0]=attachmentURL;
                res[i].url =arr.join('');
              }
              this.fileList.push({
                name: res[i].url,
                url: res[i].url,
                attachmentId: res[i].attachmentId,
                fileName: res[i].fileName
              });
            }
          }
        })
      },
      cleanFiles(){
        this.fileList=[];
      },
      /*获取附件列表*/
      getFiles() {
        return this.fileList;
      },


      // 上传前校检格式和大小
      handleBeforeUpload(file) {
        console.log("!23213123")
        // 校检文件类型
        if (this.fileType) {
          let fileExtension = "";
          if (file.name.lastIndexOf(".") > -1) {
            fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
          }
          const isTypeOk = this.fileType.some((type) => {
            if (file.type.indexOf(type) > -1) return true;
            if (fileExtension && fileExtension.indexOf(type) > -1) return true;
            return false;
          });
          if (!isTypeOk) {
            this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
            this.waitRemove = true;
            return false;
          }
        }
        // 校检文件大小
        if (this.fileSize) {
          const isLt = file.size / 1024 / 1024 < this.fileSize;
          if (!isLt) {
            this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
            return false;
          }
        }

        this.loading = this.$loading({
          lock: true,
          text: '文件上传中',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        });
        return true;
      },
      // 文件个数超出
      handleExceed() {
        this.$message.error(`上传文件数量不能超过 ${this.limit}!`);
      },
      // 上传失败
      handleUploadError(err) {
        console.log("上传失败",err)
        if(this.loading){
          this.loading.close();
        }
        this.$message.error("上传失败, 请重试");

      },
      // 上传成功回调
      handleUploadSuccess(res, file) {
        console.log("上传成功",res)
        this.$message.success("上传成功");
        this.fileList.push({
          name: res.data.url,
          url: res.data.url,
          attachmentId: res.data.id,
          fileName: res.data.fileName,
        });
        // updateAttachmentType(res.data.attachmentId,this.uploadPm.attachmentType,this.uploadPm.fieldCode);

        //告诉父页面更新fileIds
        this.$emit("notice", this.getFileIds());
        this.loading.close();
        this.loading = null;
      },
      // 删除文件
      handleDelete: function (index) {
        console.log("删除附件")
        //#todo 这里要先从服务器删除,在删除列表
        //删除前先拿到id
        let fileListElement = this.fileList[index];
        //去服务器删除附件表和附件
        delFile(fileListElement.attachmentId).then(res => {
          if (res) {
            //#todo 判断服务器的删除状态 成功则把前端列表清除
            this.fileList.splice(index, 1);
            //通知父页面更新fileIds
            this.$emit("notice", this.getFileIds());
            // this.$emit("callback", true,fileListElement);
          }
        })

      },

      //初始化父页面传来的相关配置
      init: function () {
        this.isPic = this.uploadPm.attachmentType === "PICTURE"||this.uploadPm.attachmentType === "VIDEO";//判断组件应该使用照片墙还是使用列表(图片使用照片墙,其他使用列表)
        this.isRead = this.uploadPm.isRead;
        this.limit = this.uploadPm.limit;
        this.fileSize = this.uploadPm.fileSize;
        this.fileType = this.uploadPm.fileType;
        const arr = this.fileType;
        this.$nextTick(function(){
          if(this.$refs.upload){
            const inputEl = $(this.$refs.upload.$el).find('input')[0];
            let str = '';
            for(let i=0,len=arr.length;i<len;i++){
              str += (i==0?('.'+arr[i]):(',.'+arr[i]));
              if(i==len-1)
                inputEl.accept = str;
            }
          }
        });
      },
      changeIsRead: function () {
        this.isRead = !this.isRead;
      },
      setIsRead: function (flag) {
        this.uploadPm.isRead = flag;
        this.isRead = flag;
      },
      changeModel: function () {
        this.isPic = !this.isPic;
      },
      // 获取文件名称
      getFileName(name) {
        if (name.lastIndexOf("/") > -1) {
          return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
        } else {
          return "";
        }
      },
      // 对象转成指定字符串分隔
      listToString(list, separator) {
        let strs = "";
        separator = separator || ",";
        for (let i in list) {
          strs += list[i].url + separator;
        }
        return strs !== '' ? strs.substr(0, strs.length - 1) : '';
      },
      getFileIds: function () {
        this.ids = [];
        let files = this.fileList;
        for (let i in files) {
          this.ids.push(files[i].attachmentId);
        }
        return this.ids;
      }
    }
  };

  // 删除字典类型
  export function delFile(attachmentId) {
    return request({
      url: '/file/delFile',
      method: 'post',
      data: {id: attachmentId}
    })
  }

  //修改entityId
  export function updateEntityId(ids, entityId, attachmentType,callback) {
    return request({
      url: '/file/updateEntityId',
      method: 'post',
      data: {ids: ids, entityId: entityId, attachmentType: attachmentType}
    }).then(res=>{
      if(callback)
        callback();
    })
  }
  // export function updateAttachmentType(attachmentId,attachmentType,fieldCode) {
  //   return request({
  //     url: '/system/attachment/updateAttachmentType',
  //     method: 'post',
  //     data: { attachmentId: attachmentId, attachmentType: attachmentType,fieldCode:fieldCode?fieldCode:""}
  //   })
  // }

  export function getFileList(entityId) {
    return request({
      url: '/file/getListByEntityId',
      method: 'post',
      data: {entityId: entityId}
    })
  }
  export function getFileListByPm(pm) {
    return request({
      url: '/file/getFileListByPm',
      method: 'post',
      data: {entityId: pm.entityId,entityName: pm.entityName,fieldCode:pm.fieldCode}
    })
  }
</script>

<style scoped lang="scss">
  .upload-file-uploader {
    margin-bottom: 5px;
  }

  .upload-file-list .el-upload-list__item {
    border: 1px solid #e4e7ed;
    line-height: 2;
    margin-bottom: 10px;
    position: relative;
  }

  .upload-file-list .ele-upload-list__item-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: inherit;
  }

  .ele-upload-list__item-content-action .el-link {
    margin-right: 10px;
  }
  ::v-deep{
    .el-upload-list__item-thumbnail{
      position: absolute;
      left: 0px !important;
    }
    .el-icon-check{
      margin-left: -19px;
      margin-top: 12px;
    }
    #imgView{
      left:0px !important;
      .el-dialog{
        right:0px;
        margin:0px;
        left:unset !important;
        width: calc(100% - 290px) !important;
        border-top-left-radius: 20px;
        border-top-right-radius: 20px;
        bottom: 0px;
        overflow: hidden;
        height: 94%;
        position: absolute;
        .el-dialog__header{
          height: 100px;
          .el-dialog__headerbtn {
            background: red;
            width: 30px;
            height: 30px;
            border-radius: 20px;
            .el-dialog__close{
              color: white;
            }
          }
        }
        .el-dialog__body{
          background:transparent;
        }
      }
    }
  }
</style>
<style>
  .hide .el-upload--picture-card{
    display: none !important;
  }
</style>

你可能感兴趣的:(vue.js,前端,javascript)