如何自定义antd 的 upload 上传进度条(ui搞事情)

2,751 阅读1分钟

今天分享一下怎么编写上传进度条!

  • 首先需要知道怎么监听文件上传进度?
  • 然后怎么实现进度动画?
  • 怎么实现绑定 antd-form 表单

首先需要知道怎么监听文件上传进度?

  • 调查中 xhr里面有 onUploadProgress 这个方法可以知道上传时时进度,返回一个参数progressEvent有2个字段,progressEvent.loaded / progressEvent.total percent就可以知道进度,那这样就很简单了,在api调用接口传入一个回调,代码如下。
const sendOSS = (
 params: any,
 url: string,
 onUploadProgressCallback?: Function
): any => {
 return axios({
   url: url,
   data: params,
   method: 'post',
   headers: {
     'Content-Type': 'application/x-www-form-urlencoded',
   },
   onUploadProgress: (progressEvent) => {
     let percent = ((progressEvent.loaded / progressEvent.total) * 100) | 0
     onUploadProgressCallback && onUploadProgressCallback(percent)
   },
 })
}

然后怎么实现进度动画?

  • 进度动画比较简单了,就是设置宽度,然后在当前div css添加 transition: width 0.5s; 实现一个动画过度效果,代码如下下
 <div
     className="progress-line"
     style={{ width: percent + '%' }}
  ></div>

怎么实现绑定 antd-form 表单

首先表单回给组件输入value,onChange 2个方法

  • value 就是form给到数据,通过onChange 回调数据,受控组件

const fileUpload: React.FC<
 UploadFiles & {
   multiple?: boolean
   value: Array<UploadListProps>
 }
> = (props) => {
 const {
   uploadFilesProps = {},
   children,
   onUploadClose,
   multiple = false,
   formItemStyles = {},
   value,
   onChange,
 } = props
 const [fetchSendOssPolicy] = useFileHook({
   multiple,
   onChange,
   value,
 })
 const { accept } = uploadFilesProps
 const defaultUploadFilesProps = {
   beforeUpload: async (file: RcFile) => {
     console.log(accept)
     if (accept) {
       const acceptArr = accept.split(',')
       if (!acceptArr.includes(file.type)) {
         return false
       }
     }
     await fetchSendOssPolicy(file)
     return false
   },
   showUploadList: false,
   ...uploadFilesProps,
 }

 const onUploadCloseList = (item: UploadListProps) => {
   onChange &&
     onChange(value.filter((ele: UploadListProps) => ele.key != item.key))
   onUploadClose && onUploadClose(item)
 }

 return (
   <>
     <Upload {...defaultUploadFilesProps}>{children}</Upload>
     <div style={{ marginTop: 8 }}>
       <Row gutter={[12, 12]}>
         {value?.map((item: UploadListProps) => {
           return (
             <Col
               {...{ ...formItemStyle, ...formItemStyles }}
               key={encodeURIComponent(item.key)}
             >
               <UploadList
                 {...item}
                 onUploadClose={() => onUploadCloseList(item)}
               />
             </Col>
           )
         })}
       </Row>
     </div>
   </>
 )
}

//进度条
const AntUploadList = (
 item: UploadListProps & {
   onUploadClose?: (value: Record<string, any>) => void
   rightSlot?: React.ReactNode
   readonly?: boolean
 }
) => {
 const { onUploadClose, rightSlot, readonly = false } = item

 const progressDom = useRef<any>()
 const progressRafRef = useRef<any>({
   dom: null,
 })
 useEffect(() => {
   if (readonly) {
     progressDom.current.style = ' display:none'
   }
   return () => {
     window.clearTimeout(progressRafRef.current.dom)
   }
 }, [item.percent])

 const percentageDom = useMemo(() => {
   return <div className="percentage">{item.percent}%</div>
 }, [item.percent])

 useEffect(() => {
   if (item.percent == 100) {
     progressRafRef.current.dom = setTimeout(() => {
       progressDom.current.style = ' display:none'
     }, 300)
   }
 }, [item.percent])
 return (
   <div className={'progress-item'}>
     <div
       className="file"
       style={{ marginLeft: 9, width: 'calc(100% - 130px)' }}
     >
       <div className="progress-name">
         <div className="ellipsis">
           <Tooltip placement="top" title={item.name}>
             {item.name}
           </Tooltip>
         </div>

         <div
           style={{
             display: 'inline-block',
             marginLeft: 10,
             color: 'rgba(31, 35, 28, 0.6)',
           }}
         >
           <div> {(item.size ? item.size : 0 / 1024).toFixed(2)} KB</div>
         </div>
       </div>
       <div className="progress" ref={progressDom}>
         <div className="progress-bg">
           <div
             className="progress-line"
             style={{ width: item.percent + '%' }}
           ></div>
         </div>
         {percentageDom}
       </div>
     </div>
   </div>
 )
}