最近产品提出来一个需求,需要上传一组视频或者图片,支持拖拽排序,目前项目使用的antd@4x版本的Upload组件不满足此条件,我在网上找到一个很好用的插件,基于 react-sortable-hoc 实现了这个效果。各位如有需要可参考。
react-sortable-hoc,封装了具体的拖拽细节,最终目的就是实现改变数据驱动视图进行排序。相对来说使用会简单一些。但有局限性,只能用于列表拖拽。并且拖拽时展示的组件为新建的副本,在某些操作dom的时候会有奇怪的现象(一般遇不到),因为展示的不是真实dom
1. 安装 react-sortable-hoc 库:
npm install --save react-sortable-hoc npm install --save react-dnd npm install --save react-dnd-html5-backend
复制
2. 封装拖拽组件(比如在component文件下封装,):
index.tsx
import React, { CSSProperties, memo, useState } from 'react'; import { arrayMove, SortableContainer, SortableElement, SortEnd } from 'react-sortable-hoc'; import './pictureGrid.css'; import { UploadFile } from 'antd/es/upload/interface'; import { UploadChangeParam } from 'antd/lib/upload'; import { imagePreview } from '../../utils/pictureUtil'; import UploadList from 'antd/es/upload/UploadList'; import { Modal, Upload } from 'antd'; import { Props, SortableItemParams, SortableListParams } from './types'; const itemStyle: CSSProperties = { width: 104, height: 104, margin: 4, cursor: 'grab' }; const SortableItem = SortableElement((params: SortableItemParams) => ( <div style={itemStyle}> <UploadList locale={{ previewFile: '预览图片', removeFile: '删除图片' }} showDownloadIcon={false} listType={params.props.listType} onPreview={params.onPreview} onRemove={params.onRemove} items={[params.item]} /> </div> )); const listStyle: CSSProperties = { display: 'flex', flexWrap: 'wrap', maxWidth: '100%', }; const SortableList = SortableContainer((params: SortableListParams) => { return ( <div style={listStyle}> {params.items.map((item, index) => ( <SortableItem key={`${item.uid}`} index={index} item={item} props={params.props} onPreview={params.onPreview} onRemove={params.onRemove} /> ))} <Upload {...params.props} showUploadList={false} onChange={params.onChange} > {params.props.children} </Upload> </div> ); }); const PicturesGrid: React.FC<Props> = memo(({ onChange: onFileChange, ...props }) => { const [previewImage, setPreviewImage] = useState(''); const fileList = props.fileList || []; const onSortEnd = ({ oldIndex, newIndex }: SortEnd) => { onFileChange({ fileList: arrayMove(fileList, oldIndex, newIndex) }); }; const onChange = ({ fileList: newFileList }: UploadChangeParam) => { onFileChange({ fileList: newFileList }); }; const onRemove = (file: UploadFile) => { const newFileList = fileList.filter( (item) => item.uid !== file.uid ); onFileChange({ fileList: newFileList }); }; const onPreview = async (file: UploadFile) => { await imagePreview(file, ({ image }) => { setPreviewImage(image); }); }; return ( <> <SortableList // 当移动 1 之后再触发排序事件,默认是0,会导致无法触发图片的预览和删除事件 distance={1} items={fileList} onSortEnd={onSortEnd} axis="xy" helperClass="SortableHelper" props={props} onChange={onChange} onRemove={onRemove} onPreview={onPreview} /> <Modal visible={!!previewImage} footer={null} onCancel={() => setPreviewImage('')} bodyStyle={{ padding: 0 }} > <img style={{ width: '100%' }} alt="" src={previewImage} /> </Modal> </> ); }); export { PicturesGrid };
复制
pictureGrid.css
/* 拖动的时候的样式 */ .SortableHelper { box-shadow: rgba(0, 0, 0, 0.075) 0 1px 6px, rgba(0, 0, 0, 0.075) 0 1px 4px; background-color: rgb(63, 188, 207); }
复制
types.d.ts
import { UploadFile } from 'antd/es/upload/interface'; import { UploadProps } from 'antd/lib/upload'; import { UploadChangeParam } from 'antd/lib/upload/interface'; import { ReactNode } from 'react'; export type Props = { onChange: (params: { fileList: UploadFile[] }) => void; children?: ReactNode; } & UploadProps type SortableParams = { props: Omit<Props, 'onChange'>; onPreview: (file: UploadFile) => void; onRemove: (file: UploadFile) => void | boolean; } export type SortableItemParams = { item: UploadFile; } & SortableParams export type SortableListParams = { onChange: (info: UploadChangeParam) => void; items: UploadFile[]; } & SortableParams
复制
3.组件内引用
import { PicturesGrid } from '../../components/PicturesGrid'; const PictureWall = ()=>{ const [fileList, setFileList] = useState<UploadFile[]>([]); const handleChange = ({ fileList }: { fileList: UploadFile[] }) => setFileList(fileList); return ( <div> <PicturesGrid action="https://www.mocky.io/v2/5cc8019d300000980a055e76" listType="picture-card" fileList={fileList} onChange={handleChange} > {fileList.length >= 9 ? null : "上传"} </PicturesGrid> </div> ) }
复制
以上就是upload组件支持拖拽排序的方法啦,下图是实现出来的大概效果,大家可以参考一下,有问题请留言