缘由: 项目比较古老,ant使用的是4,tag不支持托拽。
使用 react-beautiful-dnd 插件进行开发。
官方地址:GitHub - atlassian/react-beautiful-dnd: Beautiful and accessible drag and drop for lists with React
官方案例:Storybook
其他参考: demo文档 最开始找到这个,后面发现不是官方地址。。
import React, { useEffect, useState } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import { Space } from 'antd';
import CheckableTag from 'antd/es/tag/CheckableTag';
const getItemKey = (itemName) => {
switch (itemName) {
case '包':
return 'clue_pkg_id';
case '租户':
return 'tenant_id';
case '通道':
return 'channel_id';
default:
return itemName;
}
};
/**
* @function 生成初始数组
* @returns {array}
* @param items
* */
const createItems = (items) =>
items.map((item, index) => ({
id: `${item}`,
content: item,
}));
/**
* @function 生成排序后的数组
* @param {array} list 排序前数组
* @param {number} startIndex 元素在被拖动前所在索引
* @param {number} endIndex 元素在被拖动后位置所在索引
* @return {array} result 排序后数组
* */
const reorder = (list, startIndex, endIndex) => {
console.log('reorder:', list, startIndex, endIndex);
const result = Array.from(list); // 深拷贝数组
if (Math.abs(startIndex - endIndex) > 1) {
if (startIndex < endIndex) {
// 将 startIndex 到 endIndex-1 的元素向前移动一位
for (let i = startIndex; i < endIndex; i++) {
result[i] = list[i + 1];
}
// 将 startIndex 元素放到 endIndex 位置
result[endIndex] = list[startIndex];
} else {
// 将 endIndex+1 到 startIndex 的元素向后移动一位
for (let i = startIndex; i > endIndex; i--) {
result[i] = list[i - 1];
}
// 将 startIndex 元素放到 endIndex 位置
result[endIndex] = list[startIndex];
}
} else {
// 如果相差为1,直接交换两个元素
[result[startIndex], result[endIndex]] = [list[endIndex], list[startIndex]];
}
return result;
};
const HeaderSearchGroupDrag = (props) => {
//['clue_pkg_id', 'tenant_id', 'channel_id']
const [items, setItems] = useState(createItems(['包', '租户', '通道']));
const [selectedTags, setSelectedTags] = useState(['包', '租户', '通道']);
useEffect(() => {
console.log('selectedTags:', selectedTags)
}, [selectedTags]);
const onDragEnd = (result) => {
console.log('onDragEnd-result:', result);
if (!result.destination) {
return;
}
const itemsR = reorder(items, result.source.index, result.destination.index);
console.log('onDragEnd:', result, itemsR);
setItems(itemsR);
};
const tagCheckHandleChange = (tag, checked) => {
const nextSelectedTags = checked
? [...selectedTags, tag]
: selectedTags.filter((t) => t !== tag);
console.log('You are interested in: ', nextSelectedTags);
setSelectedTags(nextSelectedTags);
};
/**
* @function 渲染拖拽项目
* @param {array} dragArray
* @return {array} react element
* */
const renderDragItem = () => {
let dragElement = null;
console.log('renderDragItem1212121212', items);
dragElement = items.map((item, index) => {
const dragItem = (
<Draggable key={item.content} draggableId={item.content} index={index}>
{(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<CheckableTag
checked={selectedTags.indexOf(item.content) > -1}
color="success"
onChange={(checked) => tagCheckHandleChange(item.content, checked)}
key={'CheckableTag:' + item.content}
>
{item.content}
</CheckableTag>
</div>
)}
</Draggable>
);
return dragItem;
});
return dragElement;
};
return (
<div className="root">
<DragDropContext onDragEnd={onDragEnd}>
{/* Your target */}
<Droppable droppableId="id" direction="horizontal">
{(provided) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
<Space>{renderDragItem()}</Space>
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</div>
);
};
export default HeaderSearchGroupDrag;
增加传参,排序。
import React, { useEffect, useState } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import { Space } from 'antd';
import CheckableTag from 'antd/es/tag/CheckableTag';
const getItemKey = (itemName) => {
switch (itemName) {
case '包':
return 'clue_pkg_id';
case '租户':
return 'tenant_id';
case '通道':
return 'channel_id';
default:
return itemName;
}
};
/**
* @function 生成初始数组
* @returns {array}
* @param items
* */
const createItems = (items) =>
items.map((item, index) => ({
id: `${item}`,
content: item,
}));
/**
* @function 生成排序后的数组
* @param {array} list 排序前数组
* @param {number} startIndex 元素在被拖动前所在索引
* @param {number} endIndex 元素在被拖动后位置所在索引
* @return {array} result 排序后数组
* */
const reorder = (list, startIndex, endIndex) => {
console.log('reorder:', list, startIndex, endIndex);
const result = Array.from(list); // 深拷贝数组
if (Math.abs(startIndex - endIndex) > 1) {
if (startIndex < endIndex) {
// 将 startIndex 到 endIndex-1 的元素向前移动一位
for (let i = startIndex; i < endIndex; i++) {
result[i] = list[i + 1];
}
// 将 startIndex 元素放到 endIndex 位置
result[endIndex] = list[startIndex];
} else {
// 将 endIndex+1 到 startIndex 的元素向后移动一位
for (let i = startIndex; i > endIndex; i--) {
result[i] = list[i - 1];
}
// 将 startIndex 元素放到 endIndex 位置
result[endIndex] = list[startIndex];
}
} else {
// 如果相差为1,直接交换两个元素
[result[startIndex], result[endIndex]] = [list[endIndex], list[startIndex]];
}
return result;
};
// 按照 items 的顺序 调整 selectedTags 的顺序
// selectedTags 的所有值 都包含在 items 中,可能会比 items值要少。 需要 将selectedTags 已有值 按照 items值的顺序进行调整。
const selectedTagsSort = (items, selectedTags) => {
const result = Array.from(selectedTags); // 深拷贝数组
var i = 0;
for (let j = 0; j < items.length; j++) {
var item = items[j];
if (selectedTags.includes(item.id)) {
result[i] = item.id;
i++;
}
}
return result;
};
const HeaderSearchGroupDrag = (props) => {
const { setGroupFiledList } = props;
//['clue_pkg_id', 'tenant_id', 'channel_id']
const [items, setItems] = useState(createItems(['包', '租户', '通道']));
const [selectedTags, setSelectedTags] = useState(['包', '租户', '通道']);
useEffect(() => {
console.log('selectedTags:', selectedTags);
console.log('items:', items);
// 转换为 key。
setGroupFiledList(selectedTags.map((item) => getItemKey(item)));
}, [selectedTags]);
const onDragEnd = (result) => {
if (!result.destination) {
return;
}
const itemsR = reorder(items, result.source.index, result.destination.index);
setItems(itemsR);
let sort = selectedTagsSort(itemsR, selectedTags);
setSelectedTags(sort)
};
const tagCheckHandleChange = (tag, checked) => {
const nextSelectedTags = checked
? [...selectedTags, tag]
: selectedTags.filter((t) => t !== tag);
console.log('You are interested in: ', nextSelectedTags);
let sort = selectedTagsSort(items, nextSelectedTags);
setSelectedTags(sort);
};
/**
* @function 渲染拖拽项目
* @param {array} dragArray
* @return {array} react element
* */
const renderDragItem = () => {
let dragElement = null;
dragElement = items.map((item, index) => {
const dragItem = (
<Draggable key={item.content} draggableId={item.content} index={index}>
{(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<CheckableTag
checked={selectedTags.indexOf(item.content) > -1}
color="success"
onChange={(checked) => tagCheckHandleChange(item.content, checked)}
key={'CheckableTag:' + item.content}
>
{item.content}
</CheckableTag>
</div>
)}
</Draggable>
);
return dragItem;
});
return dragElement;
};
return (
<div className="root">
<DragDropContext onDragEnd={onDragEnd}>
{/* Your target */}
<Droppable droppableId="id" direction="horizontal">
{(provided) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
<Space>{renderDragItem()}</Space>
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</div>
);
};
export default HeaderSearchGroupDrag;