dnd-kit使用方法
-
官网地址 https://docs.dndkit.com/introduction/installation
-
安装依赖文章来源:https://www.toymoban.com/news/detail-598712.html
npm install @dnd-kit/core
npm install @dnd-kit/sortable
- 简单使用
建议直接看官网,已经描述得很详细了:https://docs.dndkit.com/presets/sortable文章来源地址https://www.toymoban.com/news/detail-598712.html
封装成组件使用
效果展示
type dataType = {
id: string
title: string
}
export default () => {
const [list, setList] = useState<dataType[]>([])
useEffect(() => {
getData()
}, [])
const getData = async () => {
setTimeout(() => {
const data = new Array(10).fill('标题-').map((s,i) => (
{id: 'id-' + i, title: s + i}
))
setList(data)
}, 200);
}
const onDragEnd = (list: dataType[], ids: string[]) => {
setList(list)
}
return (
<div >
<SortListDndKit list={list} onDragEnd={onDragEnd}>
{list.map((item) => (
<SortItemDndKit key={item.id} id={item.id}>
<div>
<h4>{item.title}</h4>
</div>
</SortItemDndKit>
))}
</SortListDndKit>
</div>
)
}
注意事项
- 如果传入的是一个函数式组件,需要用一个html元素包裹住
<SortListDndKit list={list} onDragEnd={onDragEnd}>
{list.map((item) => (
<SortItemDndKit>
{/* 这里需要用html元素包裹一下 */}
<div>
<Text title='测试组件' />
</div>
</SortItemDndKit>
))}
</SortListDndKit>
- 这里的排序默认是读取
list
中的id
作为key
值的,如果key
值是其他,可以指定list
中传入的idKey
{/* newId:list中的id名称 */}
<SortListDndKit idKey="newId" list={list} onDragEnd={onDragEnd}></SortListDndKit>
- 如果内部的元素绑定了鼠标点击之类的事件,需要先阻止事件冒泡
onMouseDown={e => e.stopPropagation()}
<SortListDndKit list={list} onDragEnd={onDragEnd}>
{list.map((item) => (
<SortItemDndKit>
{/* 这里需要用html元素包裹一下 */}
<div>
<h4>这里有很多内容</h4>
{/* 这里需要阻止鼠标点击事件的冒泡 */}
<button onMouseDown={e => e.stopPropagation()} onClick={()=>console.log('点击了')} >点击</button>
</div>
</SortItemDndKit>
))}
</SortListDndKit>
组件源码
import React, { ReactNode } from 'react';
import {
DndContext,
closestCenter,
KeyboardSensor,
PointerSensor,
useSensor,
useSensors,
DragEndEvent,
MouseSensor,
} from '@dnd-kit/core';
import {
arrayMove,
SortableContext,
sortableKeyboardCoordinates,
useSortable,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
type PropsType = {
/** 需要传递的列表 */
list: any[];
/** list的key值,默认是id */
idKey?: string;
children: ReactNode;
/** 拖拽结束的回调 */
onDragEnd: (arr: any[], ids: string[]) => void;
};
/** 参考官网:https://docs.dndkit.com/presets/sortable */
/**
* 列表排序
*/
export const SortListDndKit = ({
list = [],
idKey = 'id',
children,
onDragEnd,
}: PropsType) => {
// 指定传感器,默认是全部
const sensors = useSensors(
// useSensor(PointerSensor),
useSensor(MouseSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
// 拖拽结束
const handleDragEnd = (event: DragEndEvent) => {
const { active, over } = event;
if (active.id !== over.id) {
const oldIndex = list.findIndex((item) => item[idKey] === active.id);
const newIndex = list.findIndex((item) => item[idKey] === over.id);
const ids: string[] = list.map((item) => item[idKey]);
[ids[newIndex], ids[oldIndex]] = [ids[oldIndex], ids[newIndex]];
const _val = arrayMove(list, oldIndex, newIndex);
onDragEnd(_val, ids);
}
};
return (
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<SortableContext items={list.map((item) => item[idKey])}>
{children}
</SortableContext>
</DndContext>
);
};
type SortItemType = {
id: string;
children: ReactNode;
};
/**
* 列表排序的子项
* - 函数式组件作为children,需要用html元素包裹住
* - 例:
* - \<SortItemDndKit>
* - \<div>\<Text title='测试组件' />\</div>
* - \</SortItemDndKit>
*/
export const SortItemDndKit = ({ id, children }: SortItemType) => {
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id });
const style = {
transform: CSS.Transform.toString(transform),
transition,
};
const newChild = React.Children.map(children, (child) => {
if (!React.isValidElement(child)) {
return null;
}
const childProps = {
...child.props,
ref: setNodeRef,
style,
...attributes,
...listeners,
};
return React.cloneElement(child, childProps);
});
return <>{newChild}</>;
};
到了这里,关于react 基于 dnd-kit 封装的拖拽排序组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!