react-dnd 详细教程(安装,使用)

事先声明:在此我用到了antd的组件和mock假数据,如果需要就提前安装一下。

1. 安装

npm i react-dnd react-dnd-html5-backend

2. 使用

        2.1 首先需要将DndProvider注入

import React, { useState, createContext } from "react"
import Tree from "./pages/Tree"
import Box from "./pages/Box"
import Content from "./pages/Content"
import { DndProvider } from "react-dnd"
import { HTML5Backend } from "react-dnd-html5-backend"
import "./App.css"
const CountContext = createContext([])
function App() {
	const [count, setCount] = useState([])
	const arr = []
	return (
		<div className="App">
			<CountContext.Provider value={count}>
				<DndProvider backend={HTML5Backend}>
					<div style={{ display: "flex" }}>
						<div>
							<Tree></Tree>
						</div>
						<div>
							<Content arrList={arr} />
						</div>
					</div>
				</DndProvider>
			</CountContext.Provider>
		</div>
	)
}

export default App

        2.2 要记住useDrag是拖拽源,useDrop是放置源

          注意:并且两者互有关联的标识,在useDrag里声明的是type,在useDrop里接收的是accept。

                2.2.1 拖拽源文件 Tree.jsx

import { MailOutlined } from "@ant-design/icons"
import { Menu } from "antd"
import { useDrag } from "react-dnd"
import axios from "axios"

import "../../mock"
import React, { useState, useEffect } from "react"
function getItem(label, key, icon, children, type) {
	return {
		label,
		key,
		icon,
		children,
		type,
	}
}
function TableItem({ selected, tableName, dbName, remark, dataset, onClick = () => {}, onDoubleClick }) {
	const [, drag] = useDrag({
		type: "Box",
		item: { data: { ...dataset, dbName: dbName } },
	})
	return <p ref={drag}>{tableName}</p>
}

// submenu keys of first level
const rootSubmenuKeys = ["sub1", "sub2", "sub4"]
const App = () => {
	const [list, setList] = useState([])

	useEffect(() => {
		axios.get("test/list").then((res) => {
			// console.log(res.data.objectResult)
			if ((res.status = 200)) {
				// console.log(res)
				setList(res.data.objectResult.slice(0, 3))
			}
		})
	}, [])

	// const items = [getItem("Navigation One", "sub1", <MailOutlined />, [getItem("Option 1", "1"), getItem("Option 2", "2"), getItem("Option 3", "3"), getItem("Option 4", "4")])]
	// console.log(list)
	const items = [
		getItem(
			"Navigation One",
			"sub1",
			<MailOutlined />,

			list.map((item, index) =>
				getItem(
					<TableItem
						key={item.srcTableName}
						onClick={() => {
							// handleTbClick(dataset.name, item.srcTableName, item.taskId)
						}}
						dataset={item}
						tableName={item.srcTableName}
						remark={item.remark}
					/>,
				),
			),
		),
	]
	const [openKeys, setOpenKeys] = useState(["sub1"])
	const onOpenChange = (keys) => {
		const latestOpenKey = keys.find((key) => openKeys.indexOf(key) === -1)
		if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
			setOpenKeys(keys)
		} else {
			setOpenKeys(latestOpenKey ? [latestOpenKey] : [])
		}
	}
	return (
		<Menu
			mode="inline"
			openKeys={openKeys}
			onOpenChange={onOpenChange}
			style={{
				width: 256,
			}}
			items={items}
		/>
	)
}
export default App

                  2.2.2 放置源文件 Content.jsx

import React, { useState, useEffect, useCallback, useRef, forwardRef, useContext, createContext } from "react"
import { useDrop } from "react-dnd"
import { Button, Drawer, Table, Input } from "antd"

const style = {
	width: 900,
	height: 400,
	display: "flex",
	flexWrap: "wrap",
	position: "relative",
	overflow: "hidden",
	lineHeight: "60px",
	border: "1px dashed black",
}

const CountContext = createContext([])

function ERGraph() {
	const [open, setOpen] = useState(false)
	const [list, setList] = useState([])
	const [current, setCurrent] = useState(1)
	useEffect(() => {
		document.addEventListener("click", () => {
			setOpen(false)
		})
	}, [])
	const arr = useContext(CountContext)
	const graphRef = useRef(null)

	const onItem = (e) => {
		setList(e.columns)
		setOpen(!open)
		document.onkeyup = function (event) {
			if (event.key == "Backspace") {
				arr.splice(
					arr.findIndex((item) => item == e),
					1,
				)
				setCurrent(current + 1)
				console.log(arr)
			}
		}
	}
	useEffect(() => {
		setOpen(false)
	}, [current])
	const stopPropagation = (e) => {
		e.nativeEvent.stopImmediatePropagation()
	}
	const isOver = (e) => {
		console.log(e)
	}
	const onClose = () => {
		setOpen(false)
	}
	const handleAction = (e, a, b, value) => {
		console.log(e, a, b, value)
	}

	const columns = [
		{
			title: "字段",
			dataIndex: "columnName",
			key: "columnName",
		},
		{
			title: "别名",

			key: "name",
			render: (value = "", row) => <Input name="alias" onChange={(e) => handleAction("aliasChange", row, "alias", e.target.value)} />,
		},
		{
			title: "备注",
			width: 120,
			dataIndex: "remark",
			key: "remark",
		},
	]
	const [collectProps, drop] = useDrop({
		accept: "Box",
		collect: (monitor) => ({
			isActive: monitor.isOver(),
			canDrop: monitor.canDrop(),
		}),
		drop: (item, monitor) => {
			const dropPoint = monitor.getClientOffset()
			

			const dragData = item.data
			

			arr.push({ ...dragData, id: Math.floor(Math.random() * 1000 + 1) })
			console.log(arr)
			it.srcTableName))
			
		},
	})
	
	const content = collectProps.isActive ? "将 Box 组件拖动到这里" : "1"
	return (
		<div ref={drop} style={{ ...style }}>
			{arr.map((its, index) => {
				return (
					<Button
						key={index}
						style={{ width: "115px", height: "120px", border: "1px solid #000", margin: "10px 20px" }}
						onClick={(e) => {
							stopPropagation(e)
							onItem(its)
						}}
					>
						<p>{its.srcTableName}</p>
					</Button>
				)
			})}

			<Drawer
				title="Basic Drawer"
				placement="right"
				closable={true}
				onClose={onClose}
				open={open}
				getContainer={false}
				mask={false}
				style={{
					position: "absolute",
				}}
			>
				<Table dataSource={list} columns={columns} pagination={false}></Table>
				<div style={{ float: "right" }}>
					<Button type="error" onClick={onClose}>
						取消
					</Button>
					<Button type="primary" onClick={onClose}>
						保存
					</Button>
				</div>
			</Drawer>
		</div>
	)
}
export default forwardRef(ERGraph)

        Mock.js (供参考)

import Mock from "mockjs"
const TestMock = Mock.mock("test/list", "get", {
	success: true,
	"objectResult|1-10": [
		{
			srcTableName: "固定人审批",
			columns: [
				{ columnName: "model_id", columnTypeName: "BIGINT", remark: "数据模型id" },
				{ columnName: "model_name", columnTypeName: "VARCHAR", remark: "数据对象名称" },
				{ columnName: "description", columnTypeName: "VARCHAR", remark: "数据对象的描述" },
			],

			remark: "数据模型",
		},
		{
			srcTableName: "流动审批",
			columns: [
				{ columnName: "api_id", columnTypeName: "BIGINT", remark: "数据源id" },
				{ columnName: "api_name", columnTypeName: "VARCHAR", remark: "数据源名称" },
				{ columnName: "host", columnTypeName: "VARCHAR", remark: "用户元网络" },
				{ columnName: "protocol", columnTypeName: "VARCHAR", remark: "接口的协议" },
				{ columnName: "method", columnTypeName: "VARCHAR", remark: "接口调用的方法" },
				{ columnName: "path", columnTypeName: "VARCHAR", remark: "接口的调用路径" },
			],
			remark: "管理员表",
		},
		{
			srcTableName: "结束",

			remark: "结束",
		},
	],
})

        效果

 

 

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
react-dnd 是一个用于拖放操作的 React 库。它提供了一些组件和工具,使我们能够轻松地将拖动操作集成到我们的 React 应用中。 要使用 react-dnd,我们需要先安装它。可以使用 npm 命令行工具完成安装: ``` npm install --save react-dnd react-dnd-html5-backend ``` 我们需要安装 react-dndreact-dnd-html5-backend。后者是一个 HTML5 后端,它提供了一些基本的本地浏览器支持。 然后,我们需要在我们的应用程序中导入 react-dnd 的相关组件和工具。通常,我们需要导入 DragSource、DropTarget、DragDropContext 和 HTML5Backend: ``` import { DragSource, DropTarget } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; import { DragDropContext } from 'react-dnd'; ``` 接下来,我们需要创建一个 DragSource 和一个 DropTarget 组件。这些组件是我们用来定义拖放操作的核心。 DragSource 定义一个组件可以被拖动的方式,DropTarget 定义一个组件可以接收拖放的元素。 例如,创建一个简单的 DragSource 组件会像这样: ``` import { DragSource } from 'react-dnd'; const ItemTypes = { CARD: 'card' }; const cardSource = { beginDrag(props) { return { id: props.id }; } }; function collect(connect, monitor) { return { connectDragSource: connect.dragSource(), isDragging: monitor.isDragging() }; } const Card = ( <div> Drag Me! </div> ); export default DragSource(ItemTypes.CARD, cardSource, collect)(Card); ``` 这个简单的例子定义了一个拖动的卡片元素,其中 cardSource 是定义拖动行为的 Javascript 对象,beginDrag 方法返回了一个包含 id 属性的拖动项,用于标识当前拖动的卡片。 接下来,我们需要使用 DragDropContext 组件来包裹整个应用程序,并使用 HTML5Backend 作为拖放后端: ``` import { DragDropContext } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; ... export default DragDropContext(HTML5Backend)(App); ``` 这样我们就可以在应用程序中使用 DragSource 和 DropTarget 组件了。 当我们成功地拖动一个拖动源到它的目标时,它会触发 DropTarget 上的 drop 方法,我们可以在这个方法中定义我们想要发生的操作,例如重新排列、合并或删除元素。 以上就是 react-dnd 的简单使用方法。具体的实现还需要根据实际需求进行详细的设计和开发。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值