vue vxe-table vxe-form 表格表单中使用 vxe-upload 上传附件上传图片的方法、可复用,简化配置

619 阅读5分钟

官网:vxetable.cn/
Gitee:gitee.com/x-extends/v…
Github:github.com/x-extends/v…

分享项目中上传组件上传进度的用法,以及表单和表格中使用上传组件,以及如何全局封装上传组件,简化代码,可以复用配置化。 上传组件使用 vxe-upload,只需要配置好参数 upload-method 就可以自动上传,接收一个对, 包含 url、name、size 等属性。

上传附件基本用法

image.png

<template>
  <div>
    <vxe-upload v-model="fileList" multiple show-progress :upload-method="uploadMethod"></vxe-upload>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import axios from 'axios'

const fileList = ref([])

const uploadMethod = ({ file, updateProgress }) => {
  const formData = new FormData()
  formData.append('file', file)
  return axios.post('/api/pub/upload/single', formData, {
    onUploadProgress (progressEvent) {
      const percentCompleted = Math.round((progressEvent.loaded * 100) / (progressEvent.total || 0))
      // 更新进度
      updateProgress(percentCompleted)
    }
  }).then((res) => {
    // { url: '' }
    return {
      ...res.data
    }
  })
}

</script>

上传图片基本用法

{423752A8-9D91-440A-BF77-2EF89FD5C711}.png

<template>
  <div>
    <vxe-upload v-model="imgList" mode="image" multiple show-progress :upload-method="uploadMethod"></vxe-upload>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import axios from 'axios'

const imgList = ref([])

const uploadMethod = ({ file, updateProgress }) => {
  const formData = new FormData()
  formData.append('file', file)
  return axios.post('/api/pub/upload/single', formData, {
    onUploadProgress (progressEvent) {
      const percentCompleted = Math.round((progressEvent.loaded * 100) / (progressEvent.total || 0))
      updateProgress(percentCompleted)
    }
  }).then((res) => {
    // { url: '' }
    return {
      ...res.data
    }
  })
}

</script>

表单中使用

{B9085448-106A-432E-82E5-642C7F1C929B}.png

<template>
  <div>
    <vxe-form v-bind="formOptions"></vxe-form>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import axios from 'axios'

const fileList1ItemRender = reactive({
  name: 'VxeUpload',
  props: {
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const fileList2ItemRender = reactive({
  name: 'VxeUpload',
  props: {
    multiple: true,
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const imgList1ItemRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const imgList2ItemRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    multiple: true,
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const actionItemRender = reactive({
  name: 'VxeButtonGroup',
  options: [
    { content: '重置', type: 'reset' },
    { content: '提交', type: 'submit', status: 'primary' }
  ]
})

const formOptions = reactive({
  titleWidth: 120,
  data: {
    name: 'test1',
    nickname: 'Testing',
    sex: '',
    fileList1: [],
    fileList2: [
      { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
    ],
    imgList1: [],
    imgList2: [
      { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
    ]
  },
  items: [
    { field: 'name', title: '名称', span: 24, itemRender: { name: 'VxeInput' } },
    { field: 'fileList1', title: '上传附件', span: 24, itemRender: fileList1ItemRender },
    { field: 'fileList2', title: '上传附件多选', span: 24, itemRender: fileList2ItemRender },
    { field: 'imgList1', title: '上传图片', span: 24, itemRender: imgList1ItemRender },
    { field: 'imgList2', title: '上传图片多选', span: 24, itemRender: imgList2ItemRender },
    { align: 'center', span: 24, itemRender: actionItemRender }
  ]
})

</script>

表格中使用

{3BAAC2C5-8530-4903-B5AA-F4D4869B9E8A}.png

<template>
  <div>
    <vxe-grid v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import axios from 'axios'

const fileList1CellRender = reactive({
  name: 'VxeUpload',
  props: {
    readonly: true,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1,
      layout: 'horizontal'
    },
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const fileList2CellRender = reactive({
  name: 'VxeUpload',
  props: {
    multiple: true,
    showButtonText: false,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1,
      layout: 'horizontal'
    },
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const imgList1CellRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    readonly: true,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1
    },
    imageStyle: {
      width: 40,
      height: 40
    },
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const imgList2CellRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    multiple: true,
    showButtonText: false,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1
    },
    imageStyle: {
      width: 40,
      height: 40
    },
    uploadMethod ({ file }) {
      const formData = new FormData()
      formData.append('file', file)
      return axios.post('/api/pub/upload/single', formData).then((res) => {
        // { url: ''}
        return {
          ...res.data
        }
      })
    }
  }
})

const gridOptions = reactive({
  border: true,
  showOverflow: true,
  columns: [
    { type: 'seq', width: 70 },
    { field: 'name', title: 'Name', minWidth: 180 },
    { field: 'fileList1', title: '附件列表', width: 240, cellRender: fileList1CellRender },
    { field: 'fileList2', title: '上传附件', width: 300, cellRender: fileList2CellRender },
    { field: 'imgList1', title: '图片列表', width: 160, cellRender: imgList1CellRender },
    { field: 'imgList2', title: '上传图片', width: 210, cellRender: imgList2CellRender }
  ],
  data: [
    {
      id: 10001,
      name: 'Test1',
      imgList1: [],
      imgList2: [],
      fileList1: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
      ],
      fileList2: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
      ]
    },
    {
      id: 10002,
      name: 'Test2',
      imgList1: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' }
      ],
      imgList2: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' }
      ],
      fileList1: [],
      fileList2: []
    },
    {
      id: 10003,
      name: 'Test3',
      imgList1: [
        { name: 'fj577.jpg', url: 'https://vxeui.com/resource/img/fj577.jpg' }
      ],
      imgList2: [
        { name: 'fj577.jpg', url: 'https://vxeui.com/resource/img/fj577.jpg' }
      ],
      fileList1: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' },
        { name: 'fj187.jpg', url: 'https://vxeui.com/resource/img/fj187.jpg' }
      ],
      fileList2: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' },
        { name: 'fj187.jpg', url: 'https://vxeui.com/resource/img/fj187.jpg' }
      ]
    }
  ]
})

</script>

全局封装,统一接口,配置化,高复用性

以上的使用有没有发现一个问题,就是上传组件都要写上传接口,那么有没有办法统一在一个地方写上传接口呢,答案是有的,非常简单,有几种方法:

  • 第一种:将 vxe-upload 封装成自己的业务组件,直接使用业务组件就可以了。
  • 第二种:使用全局默认参数配置上传、删除、下载的等接口**(推荐,最简单且最好用的方式)**
  • 第三种:使用渲染器定义一个控件,将复用逻辑封装里面

接下来说的就是全局默认参数的用法:

import { VxeUI } from 'vxe-pc-ui'
import axios from 'axios'

VxeUI.setConfig({
	upload: {
		uploadMethod ({ file }) {
	      const formData = new FormData()
	      formData.append('file', file)
	      return axios.post('/api/pub/upload/single', formData).then((res) => {
	        // { url: ''}
	        return {
	          ...res.data
	        }
	      })
	    }
	}
})

表格使用

{91EFBBD6-6B7A-4C21-8D7F-FEE6378013C1}.png

<template>
  <div>
    <vxe-grid v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import axios from 'axios'

const fileList1CellRender = reactive({
  name: 'VxeUpload',
  props: {
    readonly: true,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1,
      layout: 'horizontal'
    }
  }
})

const fileList2CellRender = reactive({
  name: 'VxeUpload',
  props: {
    multiple: true,
    showButtonText: false,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1,
      layout: 'horizontal'
    }
  }
})

const imgList1CellRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    readonly: true,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1
    },
    imageStyle: {
      width: 40,
      height: 40
    }
  }
})

const imgList2CellRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    multiple: true,
    showButtonText: false,
    progressText: '{percent}%',
    moreConfig: {
      maxCount: 1
    },
    imageStyle: {
      width: 40,
      height: 40
    }
  }
})

const gridOptions = reactive({
  border: true,
  showOverflow: true,
  columns: [
    { type: 'seq', width: 70 },
    { field: 'name', title: 'Name', minWidth: 180 },
    { field: 'fileList1', title: '附件列表', width: 240, cellRender: fileList1CellRender },
    { field: 'fileList2', title: '上传附件', width: 300, cellRender: fileList2CellRender },
    { field: 'imgList1', title: '图片列表', width: 160, cellRender: imgList1CellRender },
    { field: 'imgList2', title: '上传图片', width: 210, cellRender: imgList2CellRender }
  ],
  data: [
    {
      id: 10001,
      name: 'Test1',
      imgList1: [],
      imgList2: [],
      fileList1: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
      ],
      fileList2: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
      ]
    },
    {
      id: 10002,
      name: 'Test2',
      imgList1: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' }
      ],
      imgList2: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' }
      ],
      fileList1: [],
      fileList2: []
    },
    {
      id: 10003,
      name: 'Test3',
      imgList1: [
        { name: 'fj577.jpg', url: 'https://vxeui.com/resource/img/fj577.jpg' }
      ],
      imgList2: [
        { name: 'fj577.jpg', url: 'https://vxeui.com/resource/img/fj577.jpg' }
      ],
      fileList1: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' },
        { name: 'fj187.jpg', url: 'https://vxeui.com/resource/img/fj187.jpg' }
      ],
      fileList2: [
        { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' },
        { name: 'fj573.jpeg', url: 'https://vxeui.com/resource/img/fj573.jpeg' },
        { name: 'fj187.jpg', url: 'https://vxeui.com/resource/img/fj187.jpg' }
      ]
    }
  ]
})

</script>

表单使用

{32E4F396-E5E4-4025-894D-EEBF1B991BC9}.png

<template>
  <div>
    <vxe-form v-bind="formOptions"></vxe-form>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import axios from 'axios'

const fileList1ItemRender = reactive({
  name: 'VxeUpload'
})

const fileList2ItemRender = reactive({
  name: 'VxeUpload',
  props: {
    multiple: true
  }
})

const imgList1ItemRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image'
  }
})

const imgList2ItemRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    multiple: true
  }
})

const actionItemRender = reactive({
  name: 'VxeButtonGroup',
  options: [
    { content: '重置', type: 'reset' },
    { content: '提交', type: 'submit', status: 'primary' }
  ]
})

const formOptions = reactive({
  titleWidth: 120,
  data: {
    name: 'test1',
    nickname: 'Testing',
    sex: '',
    fileList1: [],
    fileList2: [
      { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
    ],
    imgList1: [],
    imgList2: [
      { name: 'fj562.png', url: 'https://vxeui.com/resource/img/fj562.png' }
    ]
  },
  items: [
    { field: 'name', title: '名称', span: 24, itemRender: { name: 'VxeInput' } },
    { field: 'fileList1', title: '上传附件', span: 24, itemRender: fileList1ItemRender },
    { field: 'fileList2', title: '上传附件多选', span: 24, itemRender: fileList2ItemRender },
    { field: 'imgList1', title: '上传图片', span: 24, itemRender: imgList1ItemRender },
    { field: 'imgList2', title: '上传图片多选', span: 24, itemRender: imgList2ItemRender },
    { align: 'center', span: 24, itemRender: actionItemRender }
  ]
})

</script>

现在是不发现上传件方式统一了,上传接口统一了,代码复用了,配置简单了,没有最强,只有更强!!!

github github.com/x-extends/v… gitee gitee.com/x-extends/v…