• 技术文章 >web前端 >前端问答

    react-dnd怎么实现拖拽

    长期闲置长期闲置2022-04-29 16:49:58原创502

    实现方法:1、利用“import{DndProvider}from 'react-dnd'”定义一个可拖拽的范围;2、利用“import{useDrag}from 'react-dnd'”将DragSource包裹住组件,使其可以拖动即可。

    本教程操作环境:Windows10系统、react17.0.1版、Dell G3电脑。

    react-dnd怎么实现拖拽

    React DnD是React和Redux核心作者 Dan Abramov创造的一组React 高阶组件,可以在保持组件分离的前提下帮助构建复杂的拖放接口。

    React DnD 的需求

    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中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:React
    上一篇:react兼容什么版本的ie 下一篇:rxjs和react的区别是什么
    20期PHP线上班

    相关文章推荐

    精选22门好课,价值3725元,开通VIP免费学习!• react和reactdom有什么区别• angular、react和vue有什么区别• react的虚拟dom有什么用• react能实现依赖注入吗• react中redux有中间件吗
    1/1

    PHP中文网