第十六篇 难点突破之 Vue 中使用 ElementUi el-upload 进行手动上传文件 限制上传文件类型 大小 同名等进行限制

个人在做文件上传功能的时候,踩过不少的坑,特在此记录下,方便后续的查阅,也帮助有需要的个人在开发中,需要做文件的上传,自己踩过不少的坑,于是决定在此记录以下,方便自己后续查看,也方便有需要的朋友查阅。

实现的功能有:文件上传类型限制、文件大小限制、文件总大小限制、文件同名限制、文件下载、文件删除 和 文件预览图。

效果图如下:

1. 文件类型限制

2. 文件大小限制

3. 文件同名限制

4. 文件总大小限制

5. 文件下载和删除

6. 文件预览图就是上述的框体图片,这个是自己引入的图片,自己会放在附件处。有需要的可到  阿里巴巴icon图库官网 进行下载自己喜欢的图片。

7. 点击保存上传文件等信息

下面来说下大致的实现过程,让大家更明确一些。

前提:要手动上传文件,需要将 :auto-upload="false" 加上,指的是不要自动上传。自己书写下 :http-request="handleUplodFile" 方法,覆盖 action 即可。

自己定义了两个变量:

 fileList:[] : 是用于展示选择的文件列表的,如上面的一个个的框体。

realUploadFile:[] :这个是真实的要上传给后端的文件,该数组的类型是 二进制的Object 类型

下面直接说下关键的代码

1. 文件上传的时候,触发 on-change 事件,在这可做一些判断。文件类型限制、文件大小限制、文件同名限制和文件总大小限制等等。

    // 文件勾选触发
    changUpload(file) {
      const { uid, name, size } = file
      //   文件类型限制
      const fileTypeFlag = /^.png|.jpg|.jpeg|.gif|.txt|.doc|.docx|.xls|.xlsx|.pdf|.zip|.7z|.rar$/.test(
        name.substring(name.lastIndexOf('.')).toLowerCase()
      )
      if (!fileTypeFlag) {
        this.$message.warning(
          '文件类型只能是.png|.jpg|.jpeg|.gif|.doc|.docx|.xls|.xlsx|.pdf|.zip|.7z|.rar|.txt'
        )
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   文件大小进行校验
      if (size > 1024 * 1024 * 100) {
        this.$message.warning('文件大小不能超过100Mb')
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   文件总大小限制
      const totalSize = this.modelForm.fileList.reduce(
        (total, item) => total + item.size,
        0
      )
      if (totalSize + size > 1024 * 1024 * 100) {
        this.$message.warning('总文件大小不能超过100Mb')
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   文件重名限制
      const findCommonNameIndex = this.modelForm.fileList.findIndex(
        item => item.name == name
      )
      if (findCommonNameIndex !== -1) {
        this.$message.warning('不能上传同名的文件')
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   将上传的文件信息存入列表
      this.modelForm.fileList.push(file)
      this.realUploadFile = []
    },

2. 文件的删除和下载。删除其实就是将已经勾选的文件移除列表,下载就是创建 a 标签,通过href 的方式下载。注意:在这不推荐使用 window.open, 因为下载下来的 的文件名是 哈希名,不符合要求。

    // 移除不需要的文件
    handleRemove(file) {
      const { uid } = file
      const selectFileList = this.modelForm.fileList.filter(item => {
        return item.uid != uid
      })
      this.modelForm.fileList = selectFileList
    },
    // 下载文件
    handleDownload(file) {
      const { url, name } = file
      let downloadLink = document.createElement('a')
      downloadLink.href = url
      downloadLink.download = name
      document.body.appendChild(downloadLink)
      downloadLink.click()
      document.body.removeChild(downloadLink)
    },

3. 实际要上传的文件。:http-request="handleUplodFile" 该事件就是自己实际要上传的文件,触发该方法是需要通过  this.$refs['uploadBlock'].submit() 来进行,然后就会将需要上传的文件压入数组中。

// 要上传文件压入数组
handleUplodFile(file) {
  this.realUploadFile.push(file.file)
},
// 点击保存
handleHttpUpload() {
 this.$refs['uploadBlock'].submit()
......
}

4. 点击保存,上传文件等相关信息。这里使用到的是 FormData() 对象,通过 append 追加的方式,将文件和其他信息放入该 FromData() 对象中。

    // 点击保存
    handleHttpUpload() {
      this.$refs['uploadBlock'].submit()
      let formData = new FormData() //formdata格式
      formData.append('info', JSON.stringify(this.modelForm))
      this.realUploadFile.forEach(file => {
        formData.append('file', file, file.name)
      })
      fileUpload(formData).then(resonse => {
        console.log(resonse)
      })
    // 一定要先清空真实文件数组,免得点击几次,真实文件一直压入该数组
      this.$nextTick(() => {
        this.realUploadFile = []
      })
    },

5. 自己写的后端 api 接口,以及如何使用她

/***** api 接口******/
export function fileUpload(data) {
  return request({
    url: '/file/upload',
    method: 'post',
    data
  })
}

/*****调用api*****/
import { fileUpload } from '@/api/user'

......
fileUpload(formData).then(resonse => {
        console.log(resonse)
})

/******** 提示:若是需要查看到文件上传的进度,可以使用如下配置 ******************/

/***** api 接口******/
export function fileUpload(data, config) {
  return request({
    url: '/file/upload',
    method: 'post',
    data,
    ...config
  })
}

/*****调用api*****/
import { fileUpload } from '@/api/user'

......
const config = {
    timeout: 120000,
    onUploadProgress: function(process) {
        const num = process.loaded / process.total * 100 | 0
        // 将数据赋值给进度条
        this.processNum = num
    }
}
fileUpload(formData, config).then(resonse => {
        console.log(resonse)
})

6. 完整的demo 代码如下

<template>
  <div>
    <el-form ref="searchform" :model="modelForm" label-width="150px">
      <el-form-item label="select多选demo:" prop="selectValue">
        <el-select
          v-model="modelForm.selectValue"
          @change="changeSelect"
          multiple
          clearable
          placeholder="请选择"
        >
          <el-option key="selectAll" label="全部" value="selectAll"></el-option>
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="附件" prop="fileList">
        <el-upload
          ref="uploadBlock"
          action="#"
          list-type="picture-card"
          :file-list="modelForm.fileList"
          accept=".png,.jpg,.jpeg,.gif,.txt,.doc,.docx,.xls,.xlsx,.pdf,.zip,.7z,.rar"
          :auto-upload="false"
          :on-change="changUpload"
          :http-request="handleUplodFile"
        >
          <i slot="default" class="el-icon-plus"></i>
          <div slot="file" slot-scope="{ file }">
            <img
              class="el-upload-list__item-thumbnail"
              :src="getPreviwImg(file.name)"
              alt=""
            />
            <el-tooltip :content="file.name" placement="bottom" effect="light">
              <span class="el-upload-list__item-actions">
                <span
                  class="el-upload-list__item-delete"
                  @click="handleDownload(file)"
                >
                  <i class="el-icon-download"></i>
                </span>
                <span
                  class="el-upload-list__item-delete"
                  @click="handleRemove(file)"
                >
                  <i class="el-icon-delete"></i>
                </span>
              </span>
            </el-tooltip>
          </div>
        </el-upload>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleHttpUpload">保存</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import { fileUpload } from '@/api/user'
export default {
  data() {
    return {
      options: [
        {
          value: '选项1',
          label: '黄金糕'
        },
        {
          value: '选项2',
          label: '双皮奶'
        },
        {
          value: '选项3',
          label: '蚵仔煎'
        },
        {
          value: '选项4',
          label: '龙须面'
        },
        {
          value: '选项5',
          label: '北京烤鸭'
        }
      ],
      modelForm: {
        selectValue: [],
        fileList: []
      },
      realUploadFile: [], // 真实上传的文件
      selectAll: false // 用于标识是否全选--默认不全选
    }
  },
  created() {},
  methods: {
    changeSelect(value) {
      //  selectAll 为true 的时候,就走全选分支,全选后出现的情况就是取消权限
      if (this.selectAll) {
        this.selectAll = false
        if (value.indexOf('selectAll') > -1) {
          this.modelForm.selectValue = value.filter(p => p != 'selectAll')
        } else {
          this.modelForm.selectValue = []
        }
      } else {
        //   是否点击了‘全选’选项
        if (value.indexOf('selectAll') > -1) {
          // 有‘全选’选项,则将‘全部’和其他值放置一块
          const optionsValue = []
          this.options.forEach(item => {
            optionsValue.push(item.value)
          })
          this.modelForm.selectValue = ['selectAll', ...optionsValue]
          this.selectAll = true
        } else {
          // 若是勾选选择的长度和提供的选项长度是一样的,则是 ‘全选’
          if (value.length === this.options.length) {
            const optionsValue = []
            this.options.forEach(item => {
              optionsValue.push(item.value)
            })
            this.modelForm.selectValue = ['selectAll', ...optionsValue]
            this.selectAll = true
          } else {
            //   都是单选
            this.modelForm.selectValue = value
          }
        }
      }
      // 真实的勾选值
      const realSelect = this.modelForm.selectValue.filter(
        item => item != 'selectAll'
      )
      console.log('realSelect', realSelect)
    },
    // 移除不需要的文件
    handleRemove(file) {
      const { uid } = file
      const selectFileList = this.modelForm.fileList.filter(item => {
        return item.uid != uid
      })
      this.modelForm.fileList = selectFileList
    },
    // 下载文件
    handleDownload(file) {
      const { url, name } = file
      let downloadLink = document.createElement('a')
      downloadLink.href = url
      downloadLink.download = name
      document.body.appendChild(downloadLink)
      downloadLink.click()
      document.body.removeChild(downloadLink)
    },
    // 文件勾选触发
    changUpload(file) {
      const { uid, name, size } = file
      //   文件类型限制
      const fileTypeFlag = /^.png|.jpg|.jpeg|.gif|.txt|.doc|.docx|.xls|.xlsx|.pdf|.zip|.7z|.rar$/.test(
        name.substring(name.lastIndexOf('.')).toLowerCase()
      )
      if (!fileTypeFlag) {
        this.$message.warning(
          '文件类型只能是.png|.jpg|.jpeg|.gif|.doc|.docx|.xls|.xlsx|.pdf|.zip|.7z|.rar|.txt'
        )
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   文件大小进行校验
      if (size > 1024 * 1024 * 100) {
        this.$message.warning('文件大小不能超过100Mb')
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   文件总大小限制
      const totalSize = this.modelForm.fileList.reduce(
        (total, item) => total + item.size,
        0
      )
      if (totalSize + size > 1024 * 1024 * 100) {
        this.$message.warning('总文件大小不能超过100Mb')
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   文件重名限制
      const findCommonNameIndex = this.modelForm.fileList.findIndex(
        item => item.name == name
      )
      if (findCommonNameIndex !== -1) {
        this.$message.warning('不能上传同名的文件')
        const selectFileList = this.modelForm.fileList.filter(item => {
          return item.uid != uid
        })
        this.modelForm.fileList = selectFileList
        return
      }
      //   将上传的文件信息存入列表
      this.modelForm.fileList.push(file)
      this.realUploadFile = []
    },
    // 要上传文件压入数组
    handleUplodFile(file) {
      this.realUploadFile.push(file.file)
    },
    // 点击保存
    handleHttpUpload() {
      this.$refs['uploadBlock'].submit()
      let formData = new FormData() //formdata格式
      formData.append('info', JSON.stringify(this.modelForm))
      this.realUploadFile.forEach(file => {
        formData.append('file', file, file.name)
      })
      fileUpload(formData).then(resonse => {
        console.log(resonse)
      })
      this.$nextTick(() => {
        this.realUploadFile = []
      })
    },
    getImgUrl(image) {
      return require(`@/assets/images/file/${image}`)
    },
    getPreviwImg(filename) {
      filename = filename
        .substring(filename.lastIndexOf('.'))
        .toLowerCase()
        .split('.')[1]
      const imageObject = {
        png: 'icon-png.png',
        jpg: 'icon-jpg.png',
        jpeg: 'icon-jpeg.png',
        gif: 'icon-gif.png',
        doc: 'icon-doc.png',
        docx: 'icon-doc.png',
        xls: 'icon-xls.png',
        xlsx: 'icon-xls.png',
        pdf: 'icon-pdf.png',
        zip: 'icon-zip.png',
        '7z': 'icon-zip.png',
        rar: 'icon-zip.png',
        txt: 'icon-txt.png'
      }
      return this.getImgUrl(imageObject[filename])
    }
  }
}
</script>

<style lang="scss" scoped></style>

上述用到图片的附件:

 

上一篇:第十五篇 VUE中使用 ElementUi 的 el-select 实现全选功能

  • 16
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值