最近产品提出来一个需求,需要上传一组视频或者图片,支持拖拽排序,目前项目使用的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组件支持拖拽排序的方法啦,下图是实现出来的大概效果,大家可以参考一下,有问题请留言