標籤:方向 lis ext classlist 地址 項目 event end mes
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
原創。
react 拖拽排序