天天看點

基于阿裡Ant Design of Vue的上傳元件二次封裝

目前參與的項目使用的UI庫是阿裡的Ant Design of Vue

由于項目中多處要用到上傳元件,又不想每次照着官網的上傳元件複制多次上傳、删除、檢視圖檔事件,因為可能需要多次修改,是以自己進行了二次封裝,将上傳單張(上傳頭像需求)和多張弄到一起

<template>
  <div>
    <a-upload :action="uploadAction"
      list-type="picture-card"
      :disabled="disabled"
      :headers="headers"
      :file-list="fileList"
      :beforeUpload="beforeUpload"
      :data="{biz:bizPath}"
      :multiple="isMultiple"
      :showUploadList="isMultiple"
      @preview="handlePreview"
      @change="handleChange">
      <img v-if="!isMultiple && picUrl"
        :src="getAvatarView()"
        style="height:104px;max-width:300px" />
      <div v-else-if="(isMultiple && fileList.length < limit && !disabled) || (!isMultiple && !picUrl)">
        <a-icon type="plus" />
        <div class="ant-upload-text">{{text}}</div>
      </div>
    </a-upload>
    <a-modal :visible="previewVisible"
      :footer="null"
      @cancel="previewHandleCancel">
      <img alt="example"
        style="width: 100%"
        :src="previewImage" />
    </a-modal>
  </div>
</template>

<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
// import { getFileAccessHttpUrl } from '@/api/manage'

const getFileAccessHttpUrl = (avatar, subStr) => {
  if (!subStr) subStr = 'http'
  if (avatar && avatar.startsWith(subStr)) {
    return avatar;
  } else {
    if (avatar && avatar.length > 0 && avatar.indexOf('[') == -1) {
      return window._CONFIG['staticDomainURL'] + "/" + avatar;
    }
  }
}

const uidGenerator = () => {
  return '-' + parseInt(Math.random() * 10000 + 1, 10);
}
const getFileName = (path) => {
  if (path.lastIndexOf("\\") >= 0) {
    let reg = new RegExp("\\\\", "g");
    path = path.replace(reg, "/");
  }
  return path.substring(path.lastIndexOf("/") + 1);
}
export default {
  name: 'LImageUpload',
  data() {
    return {
      uploadAction: window._CONFIG['domianURL'] + "/sys/common/upload",
      headers: {},
      fileList: [],
      previewImage: "",
      previewVisible: false,
      picUrl: false
    }
  },
  props: {
    text: {
      type: String,
      default: '上傳'
    },
    // 父元件傳進來的已有的圖檔資料
    value: {
      type: [String, Array],
      required: false
    },
    // 後端要求攜帶的其他參數
    bizPath: {
      type: String,
      required: false,
      default: "temp"
    },
    // 隻能檢視不可上傳和删除時開啟該屬性
    disabled: {
      type: Boolean,
      required: false,
      default: false
    },
    // 是否多圖
    isMultiple: {
      type: Boolean,
      required: false,
      default: false
    },
    // 多圖情況下限制圖檔張數
    limit: {
      type: Number,
      required: false,
      default: 9
    }
  },
  watch: {
    value: {
      handler(val) {
        if (val instanceof Array) {
          this.initFileList(val.join(','))
        } else {
          this.initFileList(val)
        }
      },
      deep: true,
      immediate: true
    }
  },
  created() {
    const token = Vue.ls.get(ACCESS_TOKEN);
    this.headers = { "X-Access-Token": token }
  },
  methods: {
  	// 顯示已有圖檔
    initFileList(paths) {
      console.log('initFileList', paths)
      if (!paths || paths.length == 0) {
        this.fileList = [];
        return;
      }
      this.picUrl = true;
      let fileList = [];
      let arr = paths.split(",")
      for (var a = 0; a < arr.length; a++) {
        let url = getFileAccessHttpUrl(arr[a]);
        fileList.push({
          uid: uidGenerator(),
          name: getFileName(arr[a]),
          status: 'done',
          url: url,
          response: {
            status: "history",
            message: arr[a]
          }
        })
      }
      this.fileList = fileList
      console.log('fileList', this.fileList)
    },
    beforeUpload: function (file) {
      var fileType = file.type;
      if (fileType.indexOf('image') < 0) {
        this.$message.warning('請上傳圖檔');
        return false;
      }
    },
    // 關閉彈框
    previewHandleCancel() {
      this.previewVisible = false;
    },
    // 預覽
    handlePreview(file) {
      this.previewImage = file.url || file.preview;
      this.previewVisible = true;
    },
    // 上傳
    handleChange(info) {
      console.log('info----handleChange', info)
      this.picUrl = false;
      let fileList = info.fileList
      if (info.file.status === 'done') {
        if (info.file.response.success) {
          this.picUrl = true;
          fileList = fileList.map((file) => {
            if (file.response) {
              file.url = getFileAccessHttpUrl(file.response.message);
            }
            return file;
          });
        }
        //this.$message.success(`${info.file.name} 上傳成功!`);
      } else if (info.file.status === 'error') {
        this.$message.error(`${info.file.name} 上傳失敗.`);
      } else if (info.file.status === 'removed') {
        this.handleDelete(info.file)
      }
      this.fileList = fileList
      if (info.file.status === 'done' || info.file.status === 'removed') {
        this.handlePathChange()
      }
    },
    // 回傳父元件
    handlePathChange() {
      let uploadFiles = this.fileList
      let path = ''
      if (!uploadFiles || uploadFiles.length == 0) {
        path = ''
      }
      let arr = [];
      if (!this.isMultiple) {
        arr.push(uploadFiles[uploadFiles.length - 1].response.message)
      } else {
        for (var a = 0; a < uploadFiles.length; a++) {
          arr.push(uploadFiles[a].response.message)
        }
      }
      if (arr.length > 0) {
        path = arr.join(",")
      }
      this.$emit('change', path);
    },
    // 删除
    handleDelete(file) {

    },
    // 單圖上傳顯示最新的一張
    getAvatarView() {
      if (this.fileList.length > 0) {
        let url = this.fileList[this.fileList.length - 1].url
        return getFileAccessHttpUrl(url)
      }
    },
  },
  model: {
    prop: 'value',
    event: 'change'
  }
}
</script>
           

項目和後端互動,圖檔的位址不是完整的線上路徑,需要通過getFileAccessHttpUrl 返還一個完整的線上路徑,如果你的項目傳回的是一個完整的線上圖檔路徑,可以自己把上面代碼稍作修改使用

繼續閱讀