【Ant Vue】Upload组件-文件上传&图片上传

7,911 阅读5分钟

前言

最近经常用到上传组件,总结一下它的用法,做成一个组件供随时使用。

1. 前置需要

搭建好oss服务器
后台能够接收文件上传服务器,并返回文件对应的id

2. 文件上传

2.1 分析需求

  1. 能够上传文件(好像没说一样)
  2. 能够回显并下载文件
  3. 能够编辑已上传的文件
  4. 能够检测文件是否是符合要求(大小,格式)

2.2 根据功能写出需要的配置

以下是完整的配置项

  <a-upload
    :beforeUpload="beforeFileUpload"           // 上传前的回调,作用是判断文件格式、大小等等
    :defaultFileList="defaultFileList"         //  初始文件列表,用于回显
    :headers="headers"                         // 上传请求的请求头,存着authorization:multiple="true"                           // 支持多选上传
    :remove="handleFileRemove"                 // 上传列表删除回调,文件的删除需要自己实现
    @change="handleChange"                     // 上传的回调,分为三种
    action="/api/storage/upload"               // 对应后台api
    style="width: 60%"
  >
    <a-button>
      <a-icon type="upload"/>
      上传
    </a-button>
  </a-upload>

介绍一下@handleChange 回调,返回参数info 中存储着 filefileList 两个参数

file: 存储着当前操作的文件信息
response 是后台上传返回的结果
status 是我们判断上传上传中、完成、失败的参数

fileList: 存储着当前已上传的文件,与显示已上传列表相关联
若想初始化回显文件时,需要配置以下参数(第一个)
uid: 文件的id
name: 文件名称
status: 文件的状态,默认为done即可
url: 文件的下载链接(这里的第二个文件是刚上传的,默认没有下载链接)

2.3 js部分

2.3.1 data 部分

主要存储的是请求头回显用的文件列表(这里只存储了4个参数,可以按照实际需要增删)

data () {
  return {
    headers: {
      authorization: ''
    },
    defaultFileList: [
      {
        uid: '1',
        name: '测试',
        status: 'done',
        url: 'sss'
      }
    ]
  }
}

2.3.2 handleChange 上传回调

文件上传都会调用这个函数
info.file.status 可能为 uploadingdoneerror分别对应着上传中完成错误
defaultFileList 维护的是当前已上传的文件,最后提交使用,这里只存储了4个参数,可以按照实际需要增删

handleChange (info) {
  const file = info.file
  const status = info.file.status
  if (status === 'done') {                                       // 完成
    this.$message.success('图片上传成功...')
    const res = file.response.data                               // 上传后台返回的结果
    const item = {
      uid: res.newFileName,
      name: res.filename,
      status: 'done',
      url: res.url
    }
    this.defaultFileList.push(item)
  } else if (status === 'error') {                               // 错误
    this.$message.error(`${info.file.name} 文件上传失败`)
  }
},

2.3.3 handleFileRemove 删除文件回调

当点击了文件列表删除时的回调

handleFileRemove (file) {
  const name = file.name
  this.defaultFileList = this.defaultFileList.filter(item => {
    if (name !== item.name) return item
  })
}

2.3.4 beforeFileUpload 上传前回调

判断文件的类型,大小等等,达到上传前判断是否符合要求
ps: 这里直接返回false,并没有达到不能终止上传的结果,通过Promise返回reject()实现的

beforeFileUpload (file) {
  return new Promise((resolve, reject) => {
    const isJPG = file.type === 'image/jpeg'
    if (!isJPG) {
      this.$message.error('您只能上传jpg文件')
      return reject(false)
    }
    const isLt2M = file.size / 1024 / 1024 < 2
    if (!isLt2M) {
      this.$message.error('文件大小不能大于2MB')
      return reject(false)
    }
    this.$message.info('文件正在上传中...')
    return resolve(true)
  })
}

2.4 根据文件上传,写成了图片上传

点击可查看大图

<a-upload
  :beforeUpload="beforeImageUpload"
  :defaultFileList="defaultImageList"
  :headers="headers"
  :remove="handleImageRemove"
  @change="handleImageChange"
  @preview="handleImagePreview"
  action="/api/storage/upload"
  listType="picture-card"
  style="width: 60%"
  >
  <div v-if="defaultImageList.length < 2">
    <a-icon :type="imageLoading ? 'loading' : 'plus'"/>
    <div class="ant-upload-text">上传</div>
  </div>
</a-upload>
<a-modal :footer="null" :visible="previewVisible" @cancel="handleImageCancel">
  <img :src="previewImage" alt="example" style="width: 100%"/>
</a-modal>

data () {
  return {
  defaultImageList: [
    {
      uid: '1',
      name: 'Emilia',
      status: 'done',
      url: 'http://boot.demo.7326it.club/storage/2020021200028.jpg'
    }
  ],
  imageLoading: false,
  previewVisible: false,
  previewImage: ''
  }
}

handleImageChange (info) {
  const file = info.file
  const status = info.file.status
  if (info.file.status === 'uploading') {
    this.imageLoading = true
    return
  }
  if (status === 'done') {
    this.$message.success('图片上传成功...')
    this.imageLoading = false
    const res = file.response.data
    const item = {
      uid: res.newFileName,
      name: res.filename,
      status: 'done',
      url: res.url
    }
    this.defaultImageList.push(item)
  } else if (status === 'error') {
    this.$message.error(`${info.file.name} 图片上传失败`)
  }
},
beforeImageUpload (file) {
  return new Promise((resolve, reject) => {
    const isJPG = file.type === 'image/jpeg'
    if (!isJPG) {
      this.$message.error('您只能上传jpg文件')
      return reject(new Error('您只能上传jpg文件'))
    }
    const isLt2M = file.size / 1024 / 1024 < 2
    if (!isLt2M) {
      this.$message.error('文件大小不能大于2MB')
      return reject(new Error('文件大小不能大于2MB'))
    }
    this.$message.info('文件正在上传中...')
    return resolve(true)
  })
},
handleImageRemove (file) {
  const name = file.name
  this.defaultImageList = this.defaultImageList.filter(item => {
    if (name !== item.name) return item
  })
},
handleImagePreview (file) {
  this.previewImage = file.url || file.thumbUrl
  this.previewVisible = true
},
handleImageCancel () {
  this.previewVisible = false
}

2.5 完整上传代码(文件上传 + 图片上传)

<template>
  <a-card :bordered="false" title="上传">
    <a-row style="margin-bottom: 20px">
      <a-col :span="4">
        <div class="example-side">
          demo1:上传文件
        </div>
      </a-col>
      <a-col :span="8">
        <div class="example-side">
          <!-----------------------------------------------------------------demo1---start-->
          <a-upload
            :beforeUpload="beforeFileUpload"
            :defaultFileList="defaultFileList"
            :headers="headers"
            :multiple="true"
            :remove="handleFileRemove"
            @change="handleChange"
            action="/api/storage/upload"
            style="width: 60%"
          >
            <a-button>
              <a-icon type="upload"/>
              上传
            </a-button>
          </a-upload>
          <!-----------------------------------------------------------------demo1---end-->
        </div>
      </a-col>
      <a-col :span="12" class="example-side-row">
        <strong>新上传的是不能下载的,defaultFileList记录了当前上传的文件信息</strong>
        {{ defaultFileList }}
      </a-col>
    </a-row>

    <a-row style="margin-bottom: 20px">
      <a-col :span="4">
        <div class="example-side">
          demo2:图片上传
        </div>
      </a-col>
      <a-col :span="8">
        <div class="example-side">
          <!-----------------------------------------------------------------demo2---start-->
          <a-upload
            :beforeUpload="beforeImageUpload"
            :defaultFileList="defaultImageList"
            :headers="headers"
            :remove="handleImageRemove"
            @change="handleImageChange"
            @preview="handleImagePreview"
            action="/api/storage/upload"
            listType="picture-card"
            style="width: 60%"
          >
            <div v-if="defaultImageList.length < 2">
              <a-icon :type="imageLoading ? 'loading' : 'plus'"/>
              <div class="ant-upload-text">上传</div>
            </div>
          </a-upload>
          <a-modal :footer="null" :visible="previewVisible" @cancel="handleImageCancel">
            <img :src="previewImage" alt="example" style="width: 100%"/>
          </a-modal>
          <!-----------------------------------------------------------------demo2---end-->
        </div>
      </a-col>
      <a-col :span="12" class="example-side-row">
        {{ defaultImageList }}
      </a-col>
    </a-row>

  </a-card>
</template>

<script>

export default {
  name: 'UploadBox',
  data () {
    return {
      headers: {
        authorization: ''
      },
      // --------- file-upload----start
      defaultFileList: [
        {
          uid: '1',
          name: '测试',
          status: 'done',
          url: 'sss'
        }
      ],
      // --------- file-upload----end

      // --------- img-upload----start
      defaultImageList: [
        {
          uid: '1',
          name: 'Emilia',
          status: 'done',
          url: 'http://boot.demo.7326it.club/storage/2020021200028.jpg'
        }
      ],
      imageLoading: false,
      previewVisible: false,
      previewImage: ''
      // --------- img-upload----end
    }
  },
  created () {
    this.headers.authorization = 'Bearer ' + this.$store.state.user.token
  },
  methods: {
    // ---------------------------------------------file--start--
    handleChange (info) {
      const file = info.file
      const status = info.file.status
      if (status === 'done') {
        this.$message.success('图片上传成功...')
        const res = file.response.data
        const item = {
          uid: res.newFileName,
          name: res.filename,
          status: 'done',
          url: res.url
        }
        this.defaultFileList.push(item)
      } else if (status === 'error') {
        this.$message.error(`${info.file.name} 文件上传失败`)
      }
    },
    handleFileRemove (file) {
      const name = file.name
      this.defaultFileList = this.defaultFileList.filter(item => {
        if (name !== item.name) return item
      })
    },
    beforeFileUpload (file) {
      return new Promise((resolve, reject) => {
        const isJPG = file.type === 'image/jpeg'
        if (!isJPG) {
          this.$message.error('您只能上传jpg文件')
          return reject(new Error('您只能上传jpg文件'))
        }
        const isLt2M = file.size / 1024 / 1024 < 2
        if (!isLt2M) {
          this.$message.error('文件大小不能大于2MB')
          return reject(new Error('文件大小不能大于2MB'))
        }
        this.$message.info('文件正在上传中...')
        return resolve(true)
      })
    },
    // ---------------------------------------------file--end
    // ---------------------------------------------img--start
    handleImageChange (info) {
      const file = info.file
      const status = info.file.status
      if (info.file.status === 'uploading') {
        this.imageLoading = true
        return
      }
      if (status === 'done') {
        this.$message.success('图片上传成功...')
        this.imageLoading = false
        const res = file.response.data
        const item = {
          uid: res.newFileName,
          name: res.filename,
          status: 'done',
          url: res.url
        }
        this.defaultImageList.push(item)
      } else if (status === 'error') {
        this.$message.error(`${info.file.name} 图片上传失败`)
      }
    },
    beforeImageUpload (file) {
      return new Promise((resolve, reject) => {
        const isJPG = file.type === 'image/jpeg'
        if (!isJPG) {
          this.$message.error('您只能上传jpg文件')
          return reject(new Error('您只能上传jpg文件'))
        }
        const isLt2M = file.size / 1024 / 1024 < 2
        if (!isLt2M) {
          this.$message.error('文件大小不能大于2MB')
          return reject(new Error('文件大小不能大于2MB'))
        }
        this.$message.info('文件正在上传中...')
        return resolve(true)
      })
    },
    handleImageRemove (file) {
      const name = file.name
      this.defaultImageList = this.defaultImageList.filter(item => {
        if (name !== item.name) return item
      })
    },
    handleImagePreview (file) {
      this.previewImage = file.url || file.thumbUrl
      this.previewVisible = true
    },
    handleImageCancel () {
      this.previewVisible = false
    }
    // ---------------------------------------------img--end
  }
}
</script>

<style scoped>
	.example-side {
		display: flex;
		flex-direction: row;
		padding-left: 50px;
	}

	.example-side-row {
		display: flex;
		flex-direction: column;
		padding-left: 50px;
	}

	.example-center {
		display: flex;
		flex-direction: row;
		justify-content: center;
		align-items: center;
	}
</style>