【dnd-kit】react前端做一个可以垂直拖动的无序列表
背景和效果
需要做一个垂直拖动的无序列表。因项目中其他模块已经使用了dnd-kit, 为保持一致,使用的也是dnd-kit。效果如下:
可拖拽列表示例
资料
React生态中主流拖拽库的深度对比与选型指南
选型决策矩阵
代码
importReact,{useState}from'react';import{DndContext,closestCenter,PointerSensor,useSensor}from'@dnd-kit/core';import{SortableContext,verticalListSortingStrategy,useSortable}from'@dnd-kit/sortable';import{CSS}from'@dnd-kit/utilities';constmockData=[{id:"1",name:"项目一"},{id:"2",name:"项目二"},{id:"3",name:"项目三"},{id:"4",name:"项目四"},{id:"5",name:"项目五"},{id:"6",name:"项目六"},]constDragableList=()=>{const[items,setItems]=useState(mockData);constsensor=useSensor(PointerSensor,{activationConstraint:{distance:5,},});// 可排序列表项组件constSortableItem=({item})=>{const{attributes,listeners,setNodeRef,transform,transition,isDragging,}=useSortable({id:item.id});conststyle={transform:CSS.Transform.toString(transform),// 决定拖拽效果transition,opacity:isDragging?0.5:1,cursor:'grab',padding:'12px',margin:'8px 0',backgroundColor:'#f8f9fa',border:'1px solid #dee2e6',borderRadius:'4px',userSelect:'none',};return(<div ref={setNodeRef}style={style}{...attributes}{...listeners}>// 如果拖拽的模块更复杂,写在这个return里{item.name}</div>);};consthandleDragEnd=(event)=>{const{active,over}=event;if(active.id!==over?.id){setItems((items)=>{constoldIndex=items.findIndex(item=>item.id===active.id);constnewIndex=items.findIndex(item=>item.id===over.id);// 重新排列数组constnewItems=[...items];const[movedItem]=newItems.splice(oldIndex,1);newItems.splice(newIndex,0,movedItem);returnnewItems;});}};return(<div style={{padding:'20px',maxWidth:'400px',margin:'0 auto'}}><h2>可拖拽列表</h2><DndContext sensors={[sensor]}collisionDetection={closestCenter}onDragEnd={handleDragEnd}><SortableContext items={items.map((item)=>item.id)}strategy={verticalListSortingStrategy}>{items.map((item)=>(<SortableItem key={item.id}item={item}/>))}</SortableContext></DndContext><div style={{marginTop:'20px',fontSize:'14px',color:'#6c757d'}}><p>拖拽说明:</p><ul><li>点击并拖动项目可重新排序</li><li>当前项目数:{items.length}</li></ul></div></div>);};exportdefaultDragableList;复杂组件
// 可排序列表项组件constSortableItem=({item})=>{const{attributes,listeners,setNodeRef,transform,transition,isDragging,}=useSortable({id:item.id});conststyle={transform:CSS.Transform.toString(transform),// 决定拖拽效果transition,opacity:isDragging?0.5:1,cursor:'grab',padding:'12px',margin:'8px 0',backgroundColor:'#f8f9fa',border:'1px solid #dee2e6',borderRadius:'4px',userSelect:'none',};return(<div ref={setNodeRef}style={style}{...attributes}{...listeners}><Tooltip><Popconfirm title="确定删除这条属性吗?"onConfirm={()=>deleteAttr()}conCancel={(e)=>{console.log(e)}}><Button>删除</Button></Popconfirm></Tooltip></div>);};