實作方法:1、利用「import{DndProvider}from 'react-dnd'」定義一個可拖曳的範圍;2、利用「import{useDrag}from 'react-dnd'」將DragSource包裹住組件,使其可以拖曳即可。
本教學操作環境:Windows10系統、react17.0.1版、Dell G3電腦。
React DnD是React和Redux核心作者Dan Abramov創造的一組React 高階元件,可以在保持元件分離的前提下幫助建構複雜的拖放接口。
React DnD 的需求
#預設使用HTML5 拖放API,但支援
#不直接操作DOM
DOM 和拖曳的來源和目標解耦
融入HTML5拖曳中竊取類型匹配和資料傳遞的想法
React DnD 的特徵
專注拖曳,不提供現成元件
React DnD提供了一組強大的原語,但它不包含任何現成元件,而是採用包裝使用者的元件並注入props 的方式。它比jQuery UI等更底層,專注於使拖放互動正確,而把視覺方面的效果例如座標限制交給使用者處理。這其實是一種關注點分離的原則,例如React DnD不打算提供可排序元件,但使用者可以基於它快速開發任何需要的自訂的可排序元件。
單向資料流
類似於React 一樣採取宣告式渲染,並且像redux 一樣採用單向資料流架構,實際上內部使用了Redux
隱藏了平台底層API的問題
HTML5拖放API充滿了陷阱和瀏覽器的不一致。 React DnD為您內部處理它們,因此用戶可以專注於開發應用程式而不是解決瀏覽器問題。
可擴展可測試
React DnD預設提供了HTML5拖放API封裝,但它也允許您提供自訂的「後端(backend)」。您可以根據觸控事件,滑鼠事件或其他內容建立自訂DnD後端。例如,內建的模擬後端可讓您測試Node環境中元件的拖放互動。
為未來做好了準備
React DnD不會匯出mixins,並且對任何元件同樣有效,無論它們是使用ES6類,createReactClass還是其他React框架創建的。而且API支援了ES7 裝飾器。
範例如下:
1.1.使用DndProvider定義一個可以拖曳的範圍
/* * @Author: muge * @Date: 2021-12-04 16:59:25 * @LastEditors: Please set LastEditors * @LastEditTime: 2021-12-08 14:24:47 */ import React, { useState } from 'react'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import SourceBox from './SourceBox'; import TargetBox from './TargetBox'; import TreeBox from './TreeBox'; const item: any[] = [ { id: 1, name: 'muge', }, { id: 2, name: 'muxi', }, { id: 3, name: 'mugege', }, ]; const Container = () => { // 当前拖拽项 const [currentList, setCurrentList] = useState<any>({}); return ( // 类似redux数据传输 需要在最外层包裹对象 <DndProvider backend={HTML5Backend}> <h1>拖拽源组件 列表-----树</h1> <div style={{ display: 'flex' }}> <div> {/* 列表拖拽源 */} {item.map((itemz: any, index: number) => ( <SourceBox setCurrentList={setCurrentList} item={itemz} key={index} /> ))} </div> {/* 注意,不要树组件整体直接设置拖拽,抽成一个组件来遍历每一项 =》自定义渲染*/} {/* 树形拖拽源 */} <TreeBox /> </div> <h1>拖拽放置目标</h1> {/* 拖拽最终放置组件 */} <TargetBox currentList={currentList} /> </DndProvider> ); }; export default Container;
2.使用DragSource 包裹住組件,使其可以進行拖曳
/* * @Author: muge * @Date: 2021-12-07 14:26:08 * @LastEditors: Please set LastEditors * @LastEditTime: 2021-12-08 14:18:52 */ import { useDrag } from 'react-dnd'; const ItemTypes = { BOX: 'box', }; const style = { border: '1px dashed gray', backgroundColor: 'white', padding: '0.5rem 1rem', marginRight: '1rem', marginBottom: '1rem', cursor: 'move', }; const SourceBox = ({ item, setCurrentList }: any) => { const [{ opacity }, drag] = useDrag( () => ({ type: ItemTypes.BOX, collect: (monitor) => ({ opacity: monitor.isDragging() ? 0.4 : 1, }), item: () => item, //返回当前列表项数据 canDrag: (monitor) => { //是否取消拖拽 console.log(monitor, 'monitor131'); return true; }, // end(currentItem, monitor) { // monitor.getDropResult(); //获取拖拽对象所处容器的数据 // monitor.didDrop(); // 当前容器能否放置拖拽对象 拖动停止时触发 monitor.didDrop() && setCurrentList(currentItem); //在容器点松开 才赋值 }, }), [], ); return ( <div ref={drag} style={{ ...style, opacity }}> {item.id}------{item.name} </div> ); }; export default SourceBox;
3.使用DropTarget 包裹住組件,使其對拖曳,懸停或dropped 的兼容項目做出反應。
/* * @Author: muge * @Date: 2021-12-07 14:26:08 * @LastEditors: Please set LastEditors * @LastEditTime: 2021-12-08 14:33:08 */ import React from 'react'; import { useDrop } from 'react-dnd'; const ItemTypes = { BOX: 'box', }; const style: any = { border: '1px solid gray', height: '15rem', width: '15rem', padding: '2rem', textAlign: 'center', }; const TargetBox = ({ currentList }: any) => { const [{ isActive, isOver, canDrop }, drop] = useDrop(() => ({ accept: ItemTypes.BOX, collect: (monitor) => ({ isActive: monitor.canDrop() && monitor.isOver(), isOver: monitor.isOver(), canDrop: monitor.canDrop(), }), // hover: (item, monitor) => { // console.log(item, 'item'); // console.log(monitor, 'monitor'); // }, })); // console.log(isOver, 'isOver'); // console.log(canDrop, 'canDrop'); return ( <div ref={drop} style={style}> {isActive ? 'Release to drop' : 'Drag item here'} <div style={{ backgroundColor: 'pink', height: 30, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 17, fontWeight: 600, width: '100%', }} > {JSON.stringify(currentList) !== '{}' ? JSON.stringify(currentList) : '当前item'} </div> </div> ); }; export default TargetBox;
到此清單拖曳即可完成
推薦學習:《react影片教學》
以上是react-dnd怎麼實現拖曳的詳細內容。更多資訊請關注PHP中文網其他相關文章!