介绍
react-beautiful-dnd 是一个 React 的拖拽库,它可以帮助你在应用中实现拖拽功能。
访问网站查看效果。
安装
npm install react-beautiful-dnd --save
使用
三个核心组件:
DragDropContext
:拖拽上下文,用于包裹整个拖拽组件,只能有一个。Droppable
:可拖拽区域,用于包裹可拖拽的元素,可以有多个。Draggable
:可拖拽元素,用于包裹可拖拽的元素,可以有多个。
1.关闭 React 的严格模式
使用前需要关闭 React 的严格模式,因为 react-beautiful-dnd 会使用到一些不兼容严格模式的 API。
如何关闭:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
)
即去掉ReactStrictMode
标签。
2.使用 App.jsx
import Task from './components/Task'
import { DragDropContext } from 'react-beautiful-dnd'
import { useState } from 'react'
import './App.less'
const tasks = [
{
id: '1',
title: 'Estudar programação',
status: 1
},
{
id: '2',
title: 'Ler livros',
status: 0
},
{
id: '3',
title: 'Fazer compras',
status: 2
},
{
id: '4',
title: 'Lavar o carro',
status: 1
}
]
function App() {
const [taskList, setTaskList] = useState(tasks)
const changeTaskStatus = (result) => {
const statusMap = {
'To-Do-Task': 0,
Pending: 1,
Completed: 2
}
const taskTitle = result.destination?.droppableId
if (!taskTitle) return
const status = statusMap[taskTitle]
setTaskList((prevState) => {
const task = prevState.find(item => item.id === result.draggableId)
task.status = status
return [...prevState]
})
}
return (
<DragDropContext
onDragEnd={ result => changeTaskStatus(result) }
>
<div className="main">
<Task title="To-Do-Task" tasks={ taskList.filter(item => item.status === 0) } />
<Task title="Pending" tasks={ taskList.filter(item => item.status === 1) } />
<Task title="Completed" tasks={ taskList.filter(item => item.status === 2) } />
</div>
</DragDropContext>
)
}
export default App
3.使用 Task.jsx
import React from 'react'
import { Draggable, Droppable } from 'react-beautiful-dnd'
import './Task.less'
const Task = ({ tasks, title }) => {
return (
<div className="list-container">
<span className="title">{ title }</span>
<ul className="list-wrapper">
<Droppable droppableId={ title }>
{
(provided, snapshot) => (
<div
ref={ provided.innerRef }
{ ...provided.droppableProps }
>
{
tasks.map((item, index) => {
// draggableId: 拖拽元素的唯一标识 必须是字符串
return <Draggable key={ item.id } draggableId={ item.id } index={ index }>
{
(provided, snapshot) => (
<div
{ ...provided.dragHandleProps }
{ ...provided.draggableProps }
ref={ provided.innerRef }
>
<li className="list-item">
<span className="item-title">{ item.title }</span>
</li>
</div>
)
}
</Draggable>
})
}
{ provided.placeholder }
</div>
)
}
</Droppable>
</ul>
</div>
)
}
export default Task
4.样式 App.less
.main {
padding: 40px;
display: flex;
justify-content: center;
gap: 20px;
}
5.样式 Task.less
.list-container {
width: 100%;
margin: 0;
padding: 10px;
max-width: 600px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
border: 1px solid #eee;
.title {
user-select: none;
}
.list-wrapper {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 0 20px;
.list-item {
width: 100%;
list-style: none;
text-align: center;
background-color: #f1c9c9;
padding: 10px 0;
cursor: pointer;
margin-top: 10px;
user-select: none;
&:hover {
background-color: #eee;
}
.list-item__text {
font-size: 18px;
font-weight: 500;
color: #333;
}
.list-item__icon {
font-size: 20px;
color: #333;
}
}
}
}