实现原理
- 利用html5的拖放api进行目标元素拖动
- 在目标元素最终拖放结束时,获取到结束时需要放置元素位置的索引
- 通过目标元素索引以及放置元素索引更新数据
- 期间可以通过h5 的 drag api进行样式控制以及拖放索引获取
实现效果
拖拽时:

拖拽后:

代码
import "./styles.css";
import React, { useEffect, useState, useRef } from "react";
const defaultItem = [
{ title: "项目1234", key: "aa" },
{ title: "项目fawe", key: "bb" },
{ title: "项目00", key: "cc" },
{ title: "项目+++", key: "dd" },
{ title: "项目@#$%23", key: "ee" },
{ title: "项目+-*/345", key: "ff" },
{ title: "项目项目项项目", key: "gg" },
{ title: "asdf wr s ", key: "hh" }
];
export default function App(props) {
// 获取显示的项目
const indicator = (window.localStorage.getItem("user-indicator") &&
JSON.parse(window.localStorage.getItem("user-indicator"))) || [
...defaultItem
];
const [list, setList] = useState([...indicator]);
const startRef = useRef(null);
const dragDiv = useRef(null);
// 初始化索引
let oriPos = -1;
// 初始化回调(如果需要)
useEffect(() => {
props && props.call && props.call();
}, []);
// 根据前后变化的索引进行数据更新
const changePosition = (dragIndex, hoverIndex) => {
// 根据市前排还是后排进行数据重组
let dataFinal = [];
if (dragIndex < hoverIndex) {
// 向后排序
let dataArr1 = [...list].splice(0, dragIndex);
let dataArr2 = [...list].splice(dragIndex + 1, hoverIndex - dragIndex);
let dataArr3 = [list[dragIndex]];
let dataArr4 = [...list].splice(hoverIndex + 1);
if (hoverIndex - dragIndex === 1) {
// 边界处理
dataArr2 = [...list].splice(hoverIndex + 1, 1);
}
dataFinal = dataFinal.concat(dataArr1, dataArr2, dataArr3, dataArr4);
} else {
// 向前排序
let dataArr1 = [...list].splice(0, hoverIndex);
let dataArr2 = [list[dragIndex]];
let dataArr3 = [...list].splice(hoverIndex, dragIndex - hoverIndex);
let dataArr4 = [...list].splice(dragIndex + 1);
if (dragIndex - hoverIndex === 1) {
dataArr3 = [...list].splice(hoverIndex, 1);
}
dataFinal = dataFinal.concat(dataArr1, dataArr2, dataArr3, dataArr4);
}
setList(dataFinal);
};
// 开始拖动时
const onDragStart = (e, index) => {
startRef.current = index;
oriPos = index;
e.target.classList.add("drag");
};
// 结束拖动时
const onDragEnd = (e, index) => {
e.target.classList.remove("drag");
dragDiv.current.getElementsByClassName("over-down").length > 0 &&
dragDiv.current
.getElementsByClassName("over-down")[0]
.classList.remove("over-down");
dragDiv.current.getElementsByClassName("over-up").length > 0 &&
dragDiv.current
.getElementsByClassName("over-up")[0]
.classList.remove("over-up");
if (startRef.current === index) {
return;
}
// 进行数据更新
changePosition(index, startRef.current);
};
// 进入元素时
const onDragEnter = (e, hoverIndex) => {
// 排除移动的元素
if (startRef.current === hoverIndex) {
return;
}
if (oriPos < hoverIndex) {
// 向下排序
e.target.classList.add("over-down");
} else if (oriPos > hoverIndex) {
// 向上排序
e.target.classList.add("over-up");
}
// 将当前移动元素的index赋值给当前拖动的元素,避免出现两个元素抖动
startRef.current = hoverIndex;
};
// 移出元素时
const onDragLeave = (e, hoverIndex) => {
e.target.classList.remove("over");
e.target.classList.remove("over-up");
e.target.classList.remove("over-down");
};
// 当正在拖动时
const onDragOver = (e) => {
e.dataTransfer.dropEffect = "link";
e.preventDefault();
};
return (
<div className="App">
<div className="indicator-list" ref={dragDiv}>
{list.map((item, index) => {
return (
<div
className="ac"
draggable
key={item.key}
onDragStart={($event) => onDragStart($event, index)}
onDragEnd={($event) => onDragEnd($event, index)}
onDragEnter={($event) => onDragEnter($event, index)}
onDragLeave={($event) => onDragLeave($event, index)}
onDragOver={($event) => onDragOver($event)}
>
{item.title}
</div>
);
})}
</div>
</div>
);
}
本文介绍了一种使用HTML5拖放API实现列表项拖拽排序的方法。通过React实现了一个可拖拽排序的列表组件,展示了如何在拖动过程中更新列表项的位置。
1356

被折叠的 条评论
为什么被折叠?



