1. 前言

手把手带你实现一个拖拽上传文件组件

1.1 你能学到

  1. 拖拽上传的API
  2. 文件的预处理

    2. 需求分析

  3. 基本的拖动、上传、点击预览

  4. 更多的配置项
  5. 可视化

    2.1 大致流程

    image.png

    2.2 组件属性

    image.png

    3. code

    3.1 上传文件功能

    借助表单 form 功能,再设置 input type为 file,来完成文件的选择。然后再用 form 的 submit 来提交。
    因为文件是二进制文件,所以要设置encType=’multiline/form-data’

    JSONPlaceholder: 提供免费的Fake API 服务

  1. <div style={{ marginTop: '100px', marginLeft: '100px' }}>
  2. <form
  3. method='post'
  4. encType='multiline/form-data'
  5. action='http://jsonplaceholder.typicode.com/posts'
  6. >
  7. <input type='file' name='FILE' />
  8. <button type='submit'>Submit</button>
  9. </form>
  10. </div>

3.2 拖拽上传功能

  1. interface DraggerProps {
  2. onFile: (file: FileList) => void
  3. }
  4. export const Dragger: FC<DraggerProps> = (props) => {
  5. const { onFile, children } = props
  6. const [dragOver, setDragOver] = useState(false)
  7. const cnames = classNames('zhou-upload-dragger', {
  8. 'is-dragover': dragOver,
  9. })
  10. const handleDrag = (e: DragEvent<HTMLElement>, over: boolean) => {
  11. e.preventDefault()
  12. setDragOver(over)
  13. }
  14. const handleDrop = (e: DragEvent<HTMLElement>) => {
  15. e.preventDefault()
  16. setDragOver(false)
  17. onFile(e.dataTransfer.files)
  18. }
  19. return (
  20. <div
  21. className={cnames}
  22. onDragOver={(e) => handleDrag(e, true)}
  23. onDragLeave={(e) => handleDrag(e, false)}
  24. onDrop={handleDrop}
  25. >
  26. <Icon icon='upload' size='5x' theme='secondary' />
  27. {children}
  28. <p>将文件拖到这里上传</p>
  29. </div>
  30. )
  31. }
  32. export default Dragger

主要用到 onDragOveronDragLeaveonDrop事件

3.3 可视化

  1. export interface ProgressProps {
  2. percent: number
  3. strokeHeight?: number
  4. showText?: boolean
  5. styles?: CSSProperties
  6. theme?: ThemeProps
  7. }
  8. const Progress: FC<ProgressProps> = (props) => {
  9. const { percent, strokeHeight, showText, styles, theme } = props
  10. return (
  11. <div className='zhou-progress-bar' style={styles}>
  12. <div
  13. className='zhou-progress-bar-outer'
  14. style={{ height: `${strokeHeight}px` }}
  15. >
  16. <div
  17. className={`zhou-progress-bar-inner color-${theme}`}
  18. style={{ width: `${percent}%` }}
  19. >
  20. {showText && (
  21. <span className='inner-text'>{`${percent}%`}</span>
  22. )}
  23. </div>
  24. </div>
  25. </div>
  26. )
  27. }

组要借助模板字符串+CSS