react拖拽 - react-sortable-hoc
推荐react18以下版本使用
npm install react-sortable-hoc@1.9.1 array-move@1.0.0 -D
简单理解就是: 包含在SortableList的SortableItem才可以拖拽,拖拽完通过array-move库对其进行重新排序.
模仿公众号配置页面开发
import { useState } from 'react';
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
import arrayMove from 'array-move';
import styles from './index.less';
import { message } from 'antd';
import { nanoid } from 'nanoid';
export default function SortableComponent() {
const [items1, setItems1] = useState([
{ name: '服务咨询', id: nanoid(10) },
{ name: '公司动态', id: nanoid(10) },
]);
const [items2, setItems2] = useState([{ name: '在线办事', id: nanoid(10) }]);
const [items3, setItems3] = useState([{ name: '需求留言', id: nanoid(10) }]);
const [current, setCurrent] = useState('');
// 子项
const SortableItem: any = SortableElement(({ value }: any) => {
return (
<div
className={styles.item}
tabIndex={0}
onClick={() => {
setCurrent(value.id);
}}
style={{
backgroundColor: value.id == current ? '#eee' : '',
}}
>
{value.name}
</div>
);
});
// 列表
const SortableList1: any = SortableContainer(({ items }: any) => {
return (
<div>
{items.map((value: any, index: number) => (
<SortableItem key={`item-${value.id}`} index={index} value={value} />
))}
</div>
);
});
const SortableList2: any = SortableContainer(({ items }: any) => {
return (
<div>
{items.map((value: any, index: number) => (
<SortableItem key={`item-${value.id}`} index={index} value={value} />
))}
</div>
);
});
const SortableList3: any = SortableContainer(({ items }: any) => {
return (
<div>
{items.map((value: any, index: number) => (
<SortableItem key={`item-${value.id}`} index={index} value={value} />
))}
</div>
);
});
function onSortEnd1({ oldIndex, newIndex }: any) {
let oldItems = [...items1];
let newArrs = arrayMove(oldItems, oldIndex, newIndex);
setItems1(newArrs);
}
function onSortEnd2({ oldIndex, newIndex }: any) {
let oldItems = [...items2];
let newArrs = arrayMove(oldItems, oldIndex, newIndex);
setItems2(newArrs);
}
function onSortEnd3({ oldIndex, newIndex }: any) {
let oldItems = [...items3];
let newArrs = arrayMove(oldItems, oldIndex, newIndex);
setItems3(newArrs);
}
// 添加接口
function add(type: number) {
setCurrent('');
if (type == 1) {
if (items1.length < 5) {
let newItem1 = [...items1];
newItem1.push({
name: '子菜单名称',
id: nanoid(10),
});
setItems1(newItem1);
} else {
message.info('只能添加5个!');
}
}
if (type == 2) {
if (items2.length < 5) {
let newItem2 = [...items2];
newItem2.push({
name: '子菜单名称',
id: nanoid(10),
});
setItems2(newItem2);
} else {
message.info('只能添加5个!');
}
}
if (type == 3) {
if (items3.length < 5) {
let newItem3 = [...items3];
newItem3.push({
name: '子菜单名称',
id: nanoid(10),
});
setItems3(newItem3);
} else {
message.info('只能添加5个!');
}
}
}
return (
<div className={styles.box}>
<div>公众号菜单</div>
<div className={styles['bottom-box']}>
<div className={styles['bottom-box-item']}>
<SortableList1 distance={1} items={items1} onSortEnd={onSortEnd1} />
<div
className={styles.addBtn}
onClick={() => {
add(1);
}}
>
+
</div>
<div
className={styles['bottomBar']}
onClick={() => {
setCurrent('one');
}}
style={{
backgroundColor: 'one' == current ? '#eee' : '',
}}
>
首页
</div>
</div>
<div
className={styles['bottom-box-item']}
style={{
left: 100,
}}
>
<SortableList2 distance={1} items={items2} onSortEnd={onSortEnd2} />
<div
className={styles.addBtn}
onClick={() => {
add(2);
}}
>
+
</div>
<div
className={styles['bottomBar']}
onClick={() => {
setCurrent('two');
}}
style={{
backgroundColor: 'two' == current ? '#eee' : '',
}}
>
关于公司
</div>
</div>
<div
className={styles['bottom-box-item']}
style={{
left: 200,
}}
>
<SortableList3 distance={1} items={items3} onSortEnd={onSortEnd3} />
<div
className={styles.addBtn}
onClick={() => {
add(3);
}}
>
+
</div>
<div
className={styles['bottomBar']}
onClick={() => {
setCurrent('three');
}}
style={{
backgroundColor: 'three' == current ? '#eee' : '',
}}
>
联系我们
</div>
</div>
</div>
</div>
);
}
.item {
width: 100px;
height: 50px;
line-height: 50px;
text-align: center;
border: 1px solid #d0d0d0;
cursor: pointer;
&:hover {
border: 1px solid #44b549;
}
}
.box {
position: relative;
width: 300px;
height: 500px;
margin: 0 0 30px 30px;
background-color: #fff;
border: 1px solid #d0d0d0;
user-select: none;
}
.addBtn {
position: relative;
width: 100px;
height: 50px;
font-size: 20px;
line-height: 50px;
text-align: center;
border: 1px solid #d0d0d0;
&:hover {
border: 1px solid #44b549;
}
}
.bottom-box {
position: absolute;
right: 0;
bottom: 0;
left: 0;
display: flex;
.bottom-box-item {
position: absolute;
bottom: 0;
width: 100px;
cursor: pointer;
.bottomBar {
flex: 1;
height: 50px;
line-height: 50px;
text-align: center;
border: 1px solid #d0d0d0;
&:hover {
border: 1px solid #44b549;
}
}
}
}
简单版本
import { useState } from "react";
import { SortableContainer, SortableElement } from "react-sortable-hoc";
import arrayMove from "array-move";
import { nanoid } from "nanoid";
export default function SortableComponent() {
const [items, setItems] = useState([
{ name: "item1", id: nanoid(10) },
{ name: "item2", id: nanoid(10) },
]);
// 子项
const SortableItem = SortableElement(({ value }) => {
return (
<div
style={{
width: "100px",
height: "50px",
lineHeight: "50px",
border: "1px solid #d0d0d0",
cursor: "pointer",
textAlign: "center",
marginTop: "10px",
}}
tabIndex={0}
>
{value.name}
</div>
);
});
// 列表
const SortableList = SortableContainer(({ items }) => {
return (
<div>
{items.map((value, index) => (
<SortableItem key={`item-${value.id}`} index={index} value={value} />
))}
</div>
);
});
function onSortEnd({ oldIndex, newIndex }) {
let oldItems = [...items];
let newArrs = arrayMove(oldItems, oldIndex, newIndex);
setItems(newArrs);
}
// distance={8} 拖拽8px才触发
return <SortableList distance={1} items={items} onSortEnd={onSortEnd} />;
}
原理都类似. 推荐使用dnd-kit,因为react-sortable-hoc不支持react18