react中實(shí)現(xiàn)拖拽排序react-dnd功能
更新時(shí)間:2023年02月06日 14:19:41 作者:waillyer
這篇文章主要介紹了react中實(shí)現(xiàn)拖拽排序react-dnd功能,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
html 拖拽排序
import React, { useState, useRef } from 'react'; import { cloneDeep } from 'lodash'; import styles from './index.less'; const defaultList = [ { id: 1, name: '11', }, { id: 2, name: '22', }, ]; export default ({ children = '', arr = [] }) => { const [list, setList] = useState([...defaultList]); const startRef = useRef(null); const changePosition = (dragIndex, hoverIndex) => { const data = cloneDeep(list); const temp = data[dragIndex]; // 交換位置 data[dragIndex] = data[hoverIndex]; data[hoverIndex] = temp; setList(data); }; const onDragStart = index => { // console.log('onDragStart', index); startRef.current = index; }; const onDragEnd = (e, index) => { e.preventDefault(); }; const onDragOver = (e, index) => { e.preventDefault(); }; const onDragEnter = (e, hoverIndex) => { e.preventDefault(); if (startRef.current === hoverIndex) { return; } startRef.current = hoverIndex; // 將當(dāng)前當(dāng)前移動到Box的index賦值給當(dāng)前拖動的box,不然會出現(xiàn)兩個(gè)盒子瘋狂抖動! changePosition(startRef.current, hoverIndex); // console.log('onDragEnd', hoverIndex, '排序'); }; return ( <div className={styles.list_container}> {list.map((item, index) => { return ( <div className={styles.list_item} draggable key={item?.id} onDragStart={$event => onDragStart(index)} onDragEnd={$event => onDragEnd($event, index)} onDragEnter={$event => onDragEnter($event, index)} onDragOver={$event => onDragOver($event, index)} > {item.name} {/* {children} */} </div> ); })} </div> ); };
拖拽組件封裝
import React, { useRef } from 'react'; import { useDrop, useDrag } from 'react-dnd'; import styles from './index.less'; // 拖拽排序 export default ({ id = '', index = '', changePosition = () => {}, className = {}, children, rowKey = '' }) => { const ref = useRef(null); // 因?yàn)闆]有定義收集函數(shù),所以返回值數(shù)組第一項(xiàng)不要 const [, drop] = useDrop({ accept: 'DragDropBox', // 只對useDrag的type的值為DragDropBox時(shí)才做出反應(yīng) hover: (item, monitor) => { // 這里用節(jié)流可能會導(dǎo)致拖動排序不靈敏 if (!ref.current) return; const dragIndex = item.index; const hoverIndex = index; if (dragIndex === hoverIndex) return; // 如果回到自己的坑,那就什么都不做 changePosition(dragIndex, hoverIndex); // 調(diào)用傳入的方法完成交換 item.index = hoverIndex; // 將當(dāng)前當(dāng)前移動到Box的index賦值給當(dāng)前拖動的box,不然會出現(xiàn)兩個(gè)盒子瘋狂抖動! }, }); const [{ isDragging }, drag] = useDrag({ item: { type: 'DragDropBox', id, index, }, collect: monitor => ({ isDragging: monitor.isDragging(), // css樣式需要 }), }); return ( // ref 這樣處理可以使得這個(gè)組件既可以被拖動也可以接受拖動 <div ref={drag(drop(ref))} style={{ opacity: isDragging ? 0.5 : 1 }} className={className.dragBox}> <span key={rowKey} className={styles.reviewer}> {children} </span> </div> ); };
使用組件
import React from 'react'; import { DndProvider } from 'react-dnd'; import { useSelector } from 'umi'; import { cloneDeep } from 'lodash'; import HTML5Backend from 'react-dnd-html5-backend'; import ReactDndDragSort from '@/components/ReactDndDragSort'; import styles from './index.less'; export default ({ currentModel, dispatch }) => { const { reviewerList = [] } = useSelector(state => state[currentModel]); const changePosition = (dragIndex, hoverIndex) => { const data = cloneDeep(reviewerList); const temp = data[dragIndex]; // 交換位置 data[dragIndex] = data[hoverIndex]; data[hoverIndex] = temp; // setBoxList(data); dispatch({ type: `${currentModel}/overrideStateProps`, payload: { reviewerList: data, }, }); }; return ( <> <div className={styles.reviewerContainer}> <DndProvider backend={HTML5Backend}> {reviewerList?.length ? ( <div style={{ display: 'flex' }}> {reviewerList.map((item, index) => { return ( <ReactDndDragSort rowKey={item?.id} index={index} id={item?.id} changePosition={changePosition} > <span key={item?.id} className={styles.reviewer}> <div className={styles.reviewerImg}> <span className="saas saas-failure1" onClick={() => { const listFilter = reviewerList.filter( (_, itemIndex) => itemIndex !== index, ); dispatch({ type: `${currentModel}/overrideStateProps`, payload: { reviewerList: listFilter, }, }); }} /> </div> <div className={styles.reviewerTxt}>{item.name}</div> </span> </ReactDndDragSort> ); })} </div> ) : null} </DndProvider> </div> </> ); };
ts 版本
import React, { useRef } from "react"; import { useDrop, useDrag } from "react-dnd"; import "./index.less"; // dnd拖拽排序 export default (props: any) => { const { id = "", index = "", changePosition = () => {}, className = "", children, rowKey = "", } = props; const ref: any = useRef(null); // 因?yàn)闆]有定義收集函數(shù),所以返回值數(shù)組第一項(xiàng)不要 const [, drop] = useDrop({ accept: "DragDropBox", // 只對useDrag的type的值為DragDropBox時(shí)才做出反應(yīng) hover: (item: any, monitor: any) => { // 這里用節(jié)流可能會導(dǎo)致拖動排序不靈敏 if (!ref.current) return; const dragIndex = item.index; const hoverIndex = index; if (dragIndex === hoverIndex) return; // 如果回到自己的坑,那就什么都不做 changePosition(dragIndex, hoverIndex); // 調(diào)用傳入的方法完成交換 item.index = hoverIndex; // 將當(dāng)前當(dāng)前移動到Box的index賦值給當(dāng)前拖動的box,不然會出現(xiàn)兩個(gè)盒子瘋狂抖動! }, }); const [{ isDragging }, drag] = useDrag(() => ({ type: "DragDropBox", item: { id, type: "DragDropBox", index }, collect: (monitor) => ({ isDragging: monitor.isDragging(), // css樣式需要 }), })); const changeRef = drag(drop(ref)); return ( // ref 這樣處理可以使得這個(gè)組件既可以被拖動也可以接受拖動 <div //@ts-ignore ref={changeRef} style={{ opacity: isDragging ? 0.5 : 1 }} className="dragBox" > <span key={rowKey} className={className}> {children} </span> </div> ); };
ts使用
import React, { useState } from "react"; import { DndProvider } from "react-dnd"; import { useSelector } from "react-redux"; //@ts-ignore import { cloneDeep } from "lodash"; import { HTML5Backend } from "react-dnd-html5-backend"; import ReactDndDragSort from "@/components/ReactDndDragSort"; import "./index.less"; console.log("HTML5Backend", HTML5Backend); export default () => { const dList = [ { id: 99, name: "組1", }, { id: 22, name: "組2", }, ]; const [reviewerList, setReviewerList] = useState(dList); const changePosition = (dragIndex: any, hoverIndex: any) => { const data = cloneDeep(reviewerList); const temp = data[dragIndex]; // 交換位置 data[dragIndex] = data[hoverIndex]; data[hoverIndex] = temp; console.log("交換完成---", data); setReviewerList(data); }; return ( <> <div className="reviewerContainer"> <DndProvider backend={HTML5Backend}> {reviewerList?.length ? ( <div> {reviewerList.map((item: any, index: any) => { return ( <ReactDndDragSort rowKey={item?.id} index={index} id={item?.id} changePosition={changePosition} > <div key={item?.id} className="reviewer"> <div className="reviewerTxt">{item.name}</div> </div> </ReactDndDragSort> ); })} </div> ) : null} </DndProvider> </div> </> ); };
到此這篇關(guān)于react中實(shí)現(xiàn)拖拽排序react-dnd的文章就介紹到這了,更多相關(guān)react-dnd拖拽排序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react項(xiàng)目中express動態(tài)路由未能匹配造成的404問題解決
本文主要介紹了react項(xiàng)目中express動態(tài)路由未能匹配造成的404問題解決,解決了白屏的問題,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09React使用Electron開發(fā)桌面端的詳細(xì)流程步驟
React是一個(gè)流行的JavaScript庫,用于構(gòu)建Web應(yīng)用程序,結(jié)合Electron框架,可以輕松地將React應(yīng)用程序打包為桌面應(yīng)用程序,本文詳細(xì)介紹了使用React和Electron開發(fā)桌面應(yīng)用程序的步驟,需要的朋友可以參考下2023-06-06React中useState的使用方法及注意事項(xiàng)
useState通過在函數(shù)組件里調(diào)用它來給組件添加一些內(nèi)部state,下面這篇文章主要給大家介紹了關(guān)于React中useState的使用方法及注意事項(xiàng)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08React合成事件及Test Utilities在Facebook內(nèi)部進(jìn)行測試
這篇文章主要介紹了React合成事件及Test Utilities在Facebook內(nèi)部進(jìn)行測試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12React 組件的狀態(tài)下移和內(nèi)容提升的操作方法
這篇文章主要介紹了React 組件的狀態(tài)下移和內(nèi)容提升,通過代碼講解了渲染性能的組件問題結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2022-11-11