Skip to content

AntDesign

antdesign 组件库常用开发技巧

图片上传

下面是图片上传组件的定义,使用 antdesign 的Upload组件进行二次封装。你需要阅读代码注释,进行相应的修改以符合你的项目需求。

下面是组件的具体代码,何俊已经加上了注释,理解阅读应该是没有问题的

import { useValidateStore } from '@/store/useValidateStore'
import classNames from 'classnames'
import { FieldValidateError } from './FieldValidateError'
import { IFieldComponent } from './types'
import { IUploadProps, UploadImage } from '../upload/UploadImage'
import { FormApi, ReactFormApi } from '@tanstack/react-form'

interface IProps extends Omit<IFieldComponent, 'children'>, IUploadProps {
  form: FormApi<any, any> & ReactFormApi<any, any>
  action?: string
  name: string
}

export function FieldUploadImage({ form, name, className, action, onSuccess, ...props }: IProps) {
  const removeError = useValidateStore((s) => s.removeError)
  return (
    <form.Field
      name={name}
      children={(field) => (
        <div className={classNames({ 'flex flex-col gap-1': props.label })}>
          {props.label && <div className='text-sm '>{props.label}</div>}
          <div onClick={() => removeError(name)}>
            <UploadImage
              defaultImage={field.state.value}
              action={action ?? '/upload/image'}
              fieldName={name}
              onSuccess={({ url }) => {
                if (onSuccess) onSuccess(url)
                else form.setFieldValue(name, url)
              }}
              className={className}
            />
            <FieldValidateError errors={field.state.meta.errors} name={name} />
          </div>
        </div>
      )}
    />
  )
}

文件上传

下面使用 antdesign 封装文件上传组件,用于处理 mp4等文件的上传处理。

组件除了可以使用 antdesign 的 props 外,增加了以下props

props说明
children组件的显示 html
onSuccess上传成功的处理函数
fieldName后台接收的文件post 数据的 name 字段

下面是组件的具体代码,何俊已经加上了注释,理解阅读应该是没有问题的

import { useAxios } from '@/hooks/useAxios'
import { UploadOutlined } from '@ant-design/icons'
import type { UploadProps } from 'antd'
import { Button, message, Progress, Upload } from 'antd'
import { UploadChangeParam } from 'antd/es/upload'
import { UploadFile as UploadFileType } from 'antd/lib'
import classNames from 'classnames'
import qs from 'qs'
import React, { useState } from 'react'

//在原有 antdesign upload 组件基础上进行props类型封装
export interface UploadFileProps extends UploadProps {
  children: React.ReactNode
  onSuccess: (res: Record<string, any>) => void
  fieldName: string
}

//上传文件
export const UploadFile: React.FC<UploadFileProps> = ({ children, onSuccess, fieldName, ...props }) => {
  //进度条
  const [percent, setPercent] = useState(0)
  //显示进度条
  const [showProgress, setShowProgress] = useState(false)
  //axios 实例用于自定义上传
  const { axiosInstance } = useAxios()

  //自定义上传处理
  async function customRequest(options: any) {
    const { action, onSuccess, file } = options
    //生成提交的 form 表单
    const form = new FormData()
    form.append('file', file)
    try {
      //fieldName会以请求参数的形式传递,方便后台根据字段名获取文件
      const response = await axiosInstance.post<Record<string, string>>(
        action + `?` + qs.stringify({ field: fieldName }),
        form,
      )
      onSuccess(response.data)
    } catch (error) {
      setShowProgress(false)
    }
  }

  //上传完成时的处理函数
  function handleUpload(info: UploadChangeParam<UploadFileType<any>>) {
    //上传中
    if (info.file.status == 'uploading') {
      //设置进度条显示
      setShowProgress(true)
      //设置上传进度
      setPercent(info.file.percent!)
    }
    //上传成功完成
    if (info.file.status == 'done') {
      //设置进度条隐藏
      setShowProgress(false)
      //进度设置为0
      setPercent(0)
      //上传成功的回调处理
      onSuccess(info.file.response)
    }
    //上传失败
    if (info.file.status == 'error') {
      setShowProgress(false)
      const error = info.file.response.message
      message.error(error || '上传失败')
    }
  }
  return (
    <Upload {...props} customRequest={customRequest} onChange={handleUpload}>
      <div className='flex justify-start items-end gap-3'>
        {children || <Button icon={<UploadOutlined />}>选择文件</Button>}
        <Progress percent={percent} className={classNames('w-[500px] opacity-0', { '!opacity-100': showProgress })} />
      </div>
    </Upload>
  )
}