vue2_二次封装a-upload组件,自定义上传预览

简介: vue2_二次封装a-upload组件,自定义上传预览

前言

大家好,我是yma16,本文分享二次封装a-upload组件,自定义上传预览。

效果

编辑

预览

不展示删除和上传

空数据

自定义图片样式

vue2 引入 andesign

要在Vue2中引入Ant Design,需要遵循以下步骤:

  1. 安装Ant Design Vue

使用npm或者yarn安装Ant Design Vue:

npm install ant-design-vue --save

yarn add ant-design-vue
  1. 引入Ant Design Vue

在Vue应用程序的入口文件中,你需要引入Ant Design Vue的主题文件以及CSS文件:

import Vue from 'vue';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
Vue.use(Antd);
  1. 使用Ant Design Vue组件

现在你可以在Vue组件中使用Ant Design Vue组件了,例如:

<template>
  <a-button type="primary">Primary Button</a-button>
</template>
<script>
export default {
  name: 'MyComponent'
}
</script>

这样就可以在Vue2中使用Ant Design Vue了。

自定义上传customRequest

入参是本地上传的文件流

async customRequest(file) {
      const form = new FormData()
      form.append('file', file.file)
      form.append('name', file.name)
      try {
        this.uploadLoading = true
        const res = await postAction(this.uploadActionUrl, form)
        if (res.success) {
          this.picUrl = true
          const length = this.fileList.length
          const url = getFileAccessHttpUrl(res.message)
          const type = res.message ? res.message.split('.')[res.message.split('.').length - 1] : 'null'
          const addFile = {
            uid: new Date().valueOf(),
            type: type,
            name: this.renderDisplayName(file.file.name),
            status: 'done',
            response: {
              status: 'done',
              message: res.message,
            },
            url: url,
            message: res.message,
            index: length,
          }
          this.fileList.push(addFile)
          this.$message.success('上传成功')
          this.$emit('change', this.fileList.map((item) => item.message).join(','))
        } else {
          this.$message.error('上传失败')
        }
        this.uploadLoading = false
      } catch (r) {
        this.uploadLoading = false
        this.$message.error('上传失败')
        console.warn(r)
      }
    }

transformFile上传前修改文件流

入参是本地上传的文件流

这里我修改文件流的名称,返回file的promise

transformFile(file) {
      return new Promise((resolve) => {
        const currentTime = new Date()
        const type = file.type.split('/')
        const renameFile = new File([file], currentTime.valueOf() + '.' + type[1], { type: file.type })
        resolve(renameFile)
      })
    }

自定义预览

handlePreview(file) {
      return new Promise((resolve, reject) => {
        try {
          resolve(this.previewFile(file))
        } catch (r) {
          reject(r)
        }
      })
    },

调整props和a-uoload一致

<template>
  <div style="display: inline-block">
    <div>
      <a-upload
        name="file"
        :accept="accept"
        :multiple="isMultiple"
        :disabled="disabled"
        :headers="headers"
        :fileList="[]"
        :customRequest="customRequest"
        :beforeUpload="beforeUpload"
        :remove="handleDelete"
        :transformFile="transformFile"
      >
        <a-button :loading="uploadLoading" v-if="!disabled && isMultiple && fileList.length < limit">
          <a-icon type="upload" /> {{text}}
        </a-button>
      </a-upload>
      <template v-if="fileList.length">
        <div v-for="(item, index) in fileList" :key="index" class="file-list-box">
          <img v-if="isImg(item.type)" :src="item.url" class="upload-icon-view" />
          <a-icon v-else-if="isPdf(item.type)" class="upload-icon-view" type="file" />
          <a-tooltip :title="item.name">
            <span class="upload-name-view">{{ item.name }}</span>
          </a-tooltip>
          <a-tooltip title="预览">
            <span style="color: #0071fc; margin: 0 20px"><a-icon type="eye" @click="handlePreview(item)" /></span>
          </a-tooltip>
          <a-tooltip title="删除">
            <span style="color: #f5222d" v-if="!disabled"><a-icon type="delete" @click="handleDelete(item)" /></span>
          </a-tooltip>
        </div>
      </template>
      <template v-else-if="disabled">
        <div style="text-align: left">
          <img :src="require('@/assets/gaoxinImgs/null-content.png')" alt="暂无数据" style="max-width: 100px" />
          <p style="text-align: center; width: 100px">暂无数据</p>
        </div>
      </template>
    </div>
    <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
      <img alt="图片" style="width: 100%; height: 100%" :src="previewImage" />
    </a-modal>
  </div>
</template>
<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { postAction, getFileAccessHttpUrl, getAction } from '@/api/manage'
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: 'JFileUpload',
  data() {
    return {
      url: window._CONFIG['pdfDomainURL'],
      staticUrl: window._CONFIG['pdfPreviewURL'],
      id: 'pdfFilePreviewIframeId',
      fileName: '',
      uploadAction: window._CONFIG['domianURL'] + '/sys/common/upload',
      uploadActionUrl: '/sys/common/upload',
      uploadLoading: false,
      picUrl: false,
      headers: {},
      token: {},
      fileList: [],
      previewImage: '',
      previewVisible: false,
    }
  },
  props: {
    accept: {
      type: String,
      default: () => 'image/*,.pdf',
    },
    limit: {
      type: Number,
      default: 10,
    },
    text: {
      type: String,
      required: false,
      default: '上传附件(图片、pdf)',
    },
    /*这个属性用于控制文件上传的业务路径*/
    bizPath: {
      type: String,
      required: false,
      default: 'temp',
    },
    value: {
      type: [String, Array],
      required: false,
    },
    disabled: {
      type: Boolean,
      required: false,
      default: false,
    },
    isMultiple: {
      type: Boolean,
      required: false,
      default: true,
    },
  },
  watch: {
    value: {
      deep: true,
      handler(val) {
        this.initFile(val)
      },
    },
  },
  created() {
    const token = Vue.ls.get(ACCESS_TOKEN)
    this.token = token
    this.headers = { 'X-Access-Token': token }
    this.initFile(this.value)
  },
  methods: {
    initFile(val) {
      if (val instanceof Array) {
        this.initFileList(val.join(','))
      } else {
        this.initFileList(val)
      }
    },
    isWord(fileType) {
      const wordTypeArray = ['doc', 'docx']
      const isWord = wordTypeArray.some((type) => {
        return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
      })
      return isWord
    },
    isExcel(fileType) {
      const excelTypeArray = ['XLS', 'XLSX', 'XLSB', 'XLSM', 'XLST', 'sheet']
      const isExcel = excelTypeArray.some((type) => {
        return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
      })
      return isExcel
    },
    isImg(fileType) {
      const imgTypeArray = ['BMP', 'JPG', 'JPEG', 'PNG', 'GIF']
      const isImgType = imgTypeArray.some((type) => {
        return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
      })
      return isImgType
    },
    isPdf(fileType) {
      const pdfTypeArray = ['PDF']
      const isPdfType = pdfTypeArray.some((type) => {
        return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
      })
      return isPdfType
    },
    renderDisplayName(name) {
      return name
    },
    async customRequest(file) {
      const form = new FormData()
      form.append('file', file.file)
      form.append('biz', this.bizPath)
      try {
        this.uploadLoading = true
        const res = await postAction(this.uploadActionUrl, form)
        if (res.success) {
          this.picUrl = true
          const length = this.fileList.length
          const url = getFileAccessHttpUrl(res.message)
          const type = res.message ? res.message.split('.')[res.message.split('.').length - 1] : 'null'
          const addFile = {
            uid: uidGenerator(),
            type: type,
            name: this.renderDisplayName(file.file.name),
            status: 'done',
            response: {
              status: 'done',
              message: res.message,
            },
            url: url,
            message: res.message,
            index: length,
          }
          this.fileList.push(addFile)
          this.$message.success('上传成功')
          this.$emit('change', this.fileList.map((item) => item.message).join(','))
        } else {
          this.$message.error('上传失败')
        }
        this.uploadLoading = false
      } catch (r) {
        this.uploadLoading = false
        this.$message.error('上传失败')
        console.warn(r)
      }
    },
    transformFile(file) {
      return new Promise((resolve) => {
        const currentTime = new Date()
        const type = file.type.split('/')
        const renameFile = new File([file], currentTime.valueOf() + '.' + type[1], { type: file.type })
        resolve(renameFile)
      })
    },
    previewPdf(file) {
      const prefixUrl = this.staticUrl
      const path = file.response.message
      const fileUrl = prefixUrl + path
      return getAction(`/mybiz/myfile/preview/${fileUrl}`).then((previewUrl) => {
        if (previewUrl.toString().indexOf('http://') === 0) {
          const page = window.open(previewUrl)
          console.warn('page', page)
        } else {
          const page = window.open('http://' + previewUrl)
          console.warn('page', page)
        }
      })
    },
    previewImg(file) {
      this.previewImage = file.url
      this.previewVisible = true
    },
    previewExcel(file) {
      console.log('previewExcel', file)
      // 创建blob对象,解析流数据
    },
    previewFile(file) {
      const fileType = file.type
      console.log('fileType', fileType)
      if (this.isImg(fileType)) {
        return this.previewImg(file)
      } else {
        return this.previewPdf(file)
      }
    },
    initFileList(paths) {
      this.fileList = []
      if (!paths || paths.length === 0) {
        return 0
      }
      paths.split(',').forEach((item, index) => {
        const url = getFileAccessHttpUrl(item)
        const name = getFileName(item)
        const type = name && name.split('.').length ? name.split('.')[name.split('.').length - 1] : 'null'
        this.fileList.push({
          uid: uidGenerator(),
          name: this.renderDisplayName(name),
          type: type,
          status: 'done',
          url: url,
          response: {
            status: 'history',
            message: item,
          },
          message: item,
          index: index,
        })
      })
    },
    beforeUpload(file) {
      console.log('file', file)
      const fileType = file.name.split('.')[file.name.split('.').length - 1]
      // console.log('fileType', fileType)
      if (!this.isImg(fileType) && !this.isPdf(fileType)) {
        this.$message.warning('请上传图片或PDF')
        return false
      }
    },
    // 自定义预览
    handlePreview(file) {
      return new Promise((resolve, reject) => {
        try {
          resolve(this.previewFile(file))
        } catch (r) {
          reject(r)
        }
      })
    },
    handleDelete(file) {
      this.fileList = this.fileList.filter((item) => item.uid!== file.uid)
    },
    handleCancel() {
      this.close()
    },
    close() {
      this.previewImage = ''
      this.previewVisible = false
    },
  },
  model: {
    prop: 'value',
    event: 'change',
  },
}
</script>
<style scoped>
.upload-name-view {
  max-width: 80px;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.upload-icon-view {
  position: relative;
  max-height: 48px;
  min-height: 48px;
  font-size: 32px;
  padding: 2px 10px 2px 2px;
  color: #0071fc;
}
.after-icon {
  line-height: 48px;
}
.file-list-box {
  position: relative;
  height: 66px;
  line-height: 48px;
  padding: 8px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  margin-top: 10px;
  width: fit-content;
}
</style>

install封装vue组件

抛出去install在入口调用即可

import JFileUpload from './JFileUpload.vue'
export default {
  install(Vue) {
    Vue.component(JFileUpload.name, JFileUpload)
  },
}

结束

本文分享到这结束,如有错误或者不足之处欢迎指出,感谢大家的阅读!


目录
相关文章
|
7月前
|
JavaScript 前端开发 算法
简化文件上传流程:学习如何封装Vue2拖拽上传组件
简化文件上传流程:学习如何封装Vue2拖拽上传组件
142 0
|
前端开发 JavaScript 安全
【前端相关】elementui使用el-upload组件实现自定义上传
【前端相关】elementui使用el-upload组件实现自定义上传
905 0
|
2月前
|
JavaScript 前端开发 数据可视化
Element Plus图片上传组件二次扩展
Element Plus图片上传组件二次扩展
97 0
|
7月前
|
前端开发
elementui_上传组件方法自定义(formData)
elementui_上传组件方法自定义(formData)
91 1
|
JavaScript 前端开发 开发者
vue封装单文件弹窗组件
  VUE想要实现一个普通弹窗,想必对于大部分前端开发者来说实现起来都是非常简单一件事情,但是如果说要封装某一个具体需求效果,可能就难倒不少同学 ,由此可见 从实现到封装这个过程是非常考验个人能力的!
148 0
|
7月前
|
JavaScript 前端开发 小程序
vue如何封装一个上传多张图片的组件
vue如何封装一个上传多张图片的组件
基于element-plus实现vue3+ts后台管理系统的组件封装(只需传入配置对象,就可以渲染出一个页面(表单+表格))
基于element-plus实现vue3+ts后台管理系统的组件封装(只需传入配置对象,就可以渲染出一个页面(表单+表格))
|
JavaScript
vue中使用上传图片组件后上传接口的方法
vue中使用上传图片组件后上传接口的方法
50 0
|
移动开发 JavaScript
Vue H5页面长按保存为图片
Vue H5页面长按保存为图片
262 1
|
JavaScript
Vue Antdv 上传组件(a-upload、a-upload-dragger)二次封装(DZMAntdvUpload)
Vue Antdv 上传组件(a-upload、a-upload-dragger)二次封装(DZMAntdvUpload)
1219 0