ant Design Vue2.0+vite+vue3+typescript+node后台项目实现使用upload一个表单上传多个图片

本文介绍了如何在Vue3项目中结合AntDesignVue2.0实现自定义上传图片功能,特别是在需要循环遍历组件并传递特定参数的情况下。作者详细阐述了遇到的问题、解决方案以及关键代码实现,包括`customRequest`的使用和上传图片的处理逻辑。文章还提供了部分关键组件的代码示例,以帮助开发者理解和优化此类功能。
摘要由CSDN通过智能技术生成

项目介绍

项目是模仿王者荣耀mobile端的后台admin管理项目,前端使用ant Design Vue2.0+vite+vue3+typescript来做,后端是node。

需求

添加添加英雄技能界面截图。

一开始使用ant design vue的upload的change来做,后来发现我这个界面的upload是需要循环遍历出来的,而change函数里面只有三个参数,无法获取每个upload的特定参数,挣扎了好久看官方文档,终于发现了customRequest这个参数,官方说明是【通过覆盖默认的上传行为,可以自定义自己的上传实现】,然并卵,官方并没有给出例子,查了半天,别人写的全都是vue2.x,没法只能自己看着2.x版本的来修改,奋斗了一天多,终于搞出了个基础版本,在此贴出一些核心实现代码,仅供各位大佬参考,还请各位大佬多多提供优化方案。

HeroEdit.vue代码

代码太多就贴出技能这块的好了,说明一下,点击添加技能按钮就会新建一个空的技能进formState.skills数组里面,然后循环遍历这个数组生成每个技能customRequest(options:any)里面的options对象中有data,可以通过:data="{index}"来携带参数,这个我们就知道每个upload对应的哪一个技能。

<a-tab-pane key="2" tab="技能">
 <a-button type="primary" @click="formState.skills.push({})">
    <template #icon><PlusOutlined /></template>添加技能</a-button
  >
  <a-row type="flex">
    <a-col
      :span="10"
      :offset="2"
      v-for="(item, index) of formState.skills"
      :key="index"
    >
      <a-form-item label="名称">
        <a-input
          v-model:value="item.name"
          placeholder="请输入技能名称"
        ></a-input>
      </a-form-item>
      <!-- :customRequest="customRequest" -->
      <a-form-item label="图标" name="icon">
        <a-upload
          v-model:avatar="item.icon"
          name="avatar"
          :data="{ index }"
          list-type="picture-card"
          class="avatar-uploader"
          :show-upload-list="false"
          action="/admin/api/upload"
          :before-upload="beforeUpload"
          :customRequest="customRequest"
        >
          <img
            v-if="formState.skills[index].icon"
            :src="formState.skills[index].icon"
            alt="avatar"
          />
          <div v-else>
            <loading-outlined v-if="loading"></loading-outlined>
            <plus-outlined v-else></plus-outlined>
            <div class="ant-upload-text">Upload</div>
          </div>
        </a-upload>
      </a-form-item>
      <a-form-item label="描述">
        <a-textarea
          v-model:value="item.description"
          placeholder="请输入技能描述"
          :rows="4"
        />
      </a-form-item>
    </a-col>
  </a-row>
</a-tab-pane>

import { message } from 'ant-design-vue'
import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue'
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface'
import {
  defineComponent,
  onMounted,
  reactive,
  ref,
  toRaw,
  UnwrapRef,
} from 'vue'
import { useRouter, useRoute } from 'vue-router'

import {
  reqAdd,
  reqGetDetail,
  reqGetList,
  reqUpdate,
  uploadImage,
} from '../../api'

interface FormState {
  name: string
  avatar: string | undefined
  title: string
  categories: string[]
  scores: object
  items1: string[]
  items2: string[]
  usageTips: string
  battleTips: string
  teamTips: string
  skills: any[]
}

function getBase64(img: any, callback: (base64Url: string) => void) {
  const reader = new FileReader()
  reader.addEventListener('load', () => callback(reader.result as string))
  reader.readAsDataURL(img)
}

export default defineComponent({
  setup() {
  	const formState: UnwrapRef<FormState> = reactive({
      name: '',
      avatar: undefined,
      title: '',
      categories: [],
      scores: {},
      items1: [],
      items2: [],
      usageTips: '',
      battleTips: '',
      teamTips: '',
      skills: [],
    })
	/**自定义上传图片 */
    const customRequest = async (options: any) => {
      // console.log('customRequest', options)
      const { filename, file, action, data, onSuccess } = options
      // 定义上传的文件
      const formData = new FormData()
      formData.append(filename, file)
      // 发送请求
      const result: any = await uploadImage(action, formData)
      // console.log(result)
      getBase64(file, (base64Url: string) => {
        formState.skills[data.index].icon = base64Url
      })
      // 调用 onSuccess 不然会一直显示loadning
      onSuccess()
    }

    const beforeUpload = (file: FileItem) => {
      // console.log('beforeUpload')
      const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
      if (!isJpgOrPng) {
        message.error('You can only upload JPG file!')
      }
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isLt2M) {
        message.error('Image must smaller than 2MB!')
      }
      return isJpgOrPng && isLt2M
    }
    return {
      customRequest,
      beforeUpload,
      formState,
      customRequest
    }
  }
})

<style>
.avatar-uploader > .ant-upload {
  width: 128px;
  height: 128px;
}
.ant-upload-select-picture-card i {
  font-size: 32px;
  color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
  margin-top: 8px;
  color: #666;
}
</style>

index.ts请求的代码

import ajax from "./ajax";
/**自定义图片上传接口 */
export const uploadImage = (url: string, data: object) => ajax(url, data, 'POST')

服务端接收请求的代码



const express = require('express')

const multer = require('multer')
const upload = multer({ dest: __dirname + '/../../public/uploads' })

const routerFile = express.Router()


// 上传图片
routerFile.post('/upload', upload.single('avatar'), async (req, res) => {
  console.log('上传图片成功')
  const file = req.file
  file.url = `http://localhost:8000/public/uploads/${file.filename}`
  res.send(file)
})


module.exports = routerFile


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值