react 拖拽排序。项目中用到了,记一笔。没有用react-dnd, 没有用react-beautiful-dnd, 因为需求简单,所以就自己撸了一个。
代码很简单
定义css, 两个动画
.drag-up { -webkit-animation: dragup ease 0.2s 1; animation: dragup ease 0.2s 1; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; background-color: red; } .drag-down { -webkit-animation: dragdown ease 0.2s 1; animation: dragdown ease 0.2s 1; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; background-color: green; } @-webkit-keyframes dragup { from { margin-top: 10px; } to { margin-top: 60px; } } @keyframes dragup { from { margin-top: 10px; } to { margin-top: 60px; } } @-webkit-keyframes dragdown { from { margin-bottom: 10px; margin-top: 60px; } to { margin-bottom: 60px; margin-top: 10px; } } @keyframes dragdown { from { margin-bottom: 10px; margin-top: 60px; } to { margin-bottom: 60px; margin-top: 10px; } }
一个是向上拖拽的动画,一个是向下拖拽的样式。
2.写组件
class List extends React.Component { constructor(props) { super(props); this.state = {...props}; } dragStart(e) { this.dragged = e.currentTarget; } dragEnd(e) { this.dragged.style.display = ‘block‘; e.target.classList.remove("drag-up"); this.over.classList.remove("drag-up"); e.target.classList.remove("drag-down"); this.over.classList.remove("drag-down"); var data = this.state.data; var from = Number(this.dragged.dataset.id); var to = Number(this.over.dataset.id); data.splice(to, 0, data.splice(from, 1)[0]); //set newIndex to judge direction of drag and drop data = data.map((doc, index)=> { doc.newIndex = index + 1; return doc; }) this.setState({data: data}); } dragOver(e) { e.preventDefault(); this.dragged.style.display = "none"; if (e.target.tagName !== "LI") { return; } //判断当前拖拽target 和 经过的target 的 newIndex const dgIndex = JSON.parse(this.dragged.dataset.item).newIndex; const taIndex = JSON.parse(e.target.dataset.item).newIndex; const animateName = dgIndex > taIndex ? "drag-up" : "drag-down"; if (this.over && e.target.dataset.item !== this.over.dataset.item) { this.over.classList.remove("drag-up", "drag-down"); } if(!e.target.classList.contains(animateName)) { e.target.classList.add(animateName); this.over = e.target; } } render() { var listItems = this.state.data.map((item, i) => { return ( <li data-id={i} key={i} style={{height: "60px", border: "solid 1px #cccccc", margin: "10px 30%", borderRadius: "5px", backgroundColor: "green", color: "#ffffff"}} draggable=‘true‘ onDragEnd={this.dragEnd.bind(this)} onDragStart={this.dragStart.bind(this)} data-item={JSON.stringify(item)} >{item.color}</li> ) }); return ( <ul onDragOver={this.dragOver.bind(this)} className ="contain"> {listItems} </ul> ) } } class App extends React.Component { constructor(props) { super(props); this.state = { data: [ { newIndex: 1, color: "red" }, { newIndex: 2, color: "green" }, { newIndex: 3, color: "blue" }, { newIndex: 4, color: "yellow" }, { newIndex: 5, color: "orange" }, { newIndex: 6, color: "black" } ] } } render() { return ( <div> <List data={this.state.data} /> </div> ) } } ReactDOM.render( <App />, document.getElementById(‘app‘), );
解释几个三个方法
1.dragStart 把 target 赋值给了this
2.dragOver 把经过的 li 赋值给了 this, 并且在经过的li上,添加对应的class, 实现动画效果。 这里比较了序号,判断当前是向哪个方向拖拽。 并且比较了 经过li是否是同一个,不是的话,移除动画效果。
3.dragEnd, 移除动画效果, 并且比较数据,setState到最新的数据。
总结, 有点dom操作的思想。
demo地址: https://codepen.io/jhonyoung/pen/PeGpNL
原创。
原文地址:https://www.cnblogs.com/jhonyoung/p/8954512.html
时间: 2024-11-02 21:23:28