基于 antd Upload 组件的图片墙实现拖拽排序

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

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值