react 拖拽组件 自由拖拽,垂直水平拖拽

react拖拽组件

最近忙着公司后台系统开发,因为需求用到了拖拽.给大家安利几个好用的拖拽组件!

1.第一个拖拽组件 antd的Tree组件

这个拖拽组件经常用于层级关系的拖拽组件 可以动态的增删改 (排序,添加子层级~父层级,修改等).

antd-Tree拖拽图片

import React,{ useEffect,useState } from "react"
import { Tree,message } from 'antd'; //导入antd 的Tree组件

export default function App() {
    const [data,setData] = useState([])
    useEffect(() => {
        if (data.length === 0) {
            //初始化数据
            setData([{ title: "组1",key: 1 },{ title: "组2",key: 2,children: [{ title: "子组1",key: 6 },{ title: "子组2",key: 7 },{ title: "子组3",key: 9 }] },{ title: "组3",key: 3 },{ title: "组4",key: 4 }])
        }
    },[data])
    //完成拖拽
    const onDrop = info => {

        /**
         *  这里是判断 拖拽之后的动作是否允许存在跨级拖拽交换位置等等...
         *  若需要判断可以取消注释
         */
        // let nodePosArr = info.node.pos.split('-')
        // let dropPosArr = info.dragNode.pos.split('-')
        // if (dropPosArr.length === nodePosArr.length && nodePosArr[1] !== dropPosArr[1]) return message.error("不可拖入其他类别")
        // if (nodePosArr.length !== dropPosArr.length) return message.error("列表禁止跨级拖拽")
        // if (!info.dropToGap) return message.error("同级列表只能互换顺序")

        const dropKey = info.node.props.eventKey;
        const dragKey = info.dragNode.props.eventKey;
        const dropPos = info.node.props.pos.split('-');
        const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);

        const loop = (data,key,callback) => {
            for (let i = 0; i < data.length; i++) {
                if (data[i].key === key) {
                    return callback(data[i],i,data);
                }
                if (data[i].children) {
                    loop(data[i].children,callback);
                }
            }
        };
        const changeData = [...data];

        // Find dragObject
        let dragObj;
        loop(changeData,dragKey,(item,index,arr) => {
            arr.splice(index,1);
            dragObj = item;
        });

        if (!info.dropToGap) {
            // Drop on the content
            loop(data,dropKey,item => {
                item.children = item.children || [];
                // where to insert 示例添加到尾部,可以是随意位置
                item.children.push(dragObj);
            });
        } else if (
            (info.node.props.children || []).length > 0 && // Has children
            info.node.props.expanded && // Is expanded
            dropPosition === 1 // On the bottom gap
        ) {
            loop(data,item => {
                item.children = item.children || [];
                // where to insert 示例添加到头部,可以是随意位置
                item.children.unshift(dragObj);
            });
        } else {
            let ar;
            let i;
            loop(data,arr) => {
                ar = arr;
                i = index;
            });
            if (dropPosition === -1) {
                ar.splice(i,dragObj);
            } else {
                ar.splice(i + 1,dragObj);
            }
        }
        //changeData就是拖拽结束后改变的数据格式,需要在这里重新赋值 即可显示最新拖拽之后的结果
        setData(changeData)
    };
    /**
     * 
     * @param {Array} selectedKeys  选中的key 数组存放,单多选
     * @param {Node} e 被选择中的node信息,可以拿到 数据源,层级关系等...
     */
    //完成选择
    const onSelect = (selectedKeys,e) => {
        console.log(selectedKeys,e);
    }
    return <>
        <Tree
            draggable //是否可以拖拽
            blockNode //是否节点占据一行	
            showLine  //	是否展示连接线
            treeData={data} //数据源 格式 Array 每项的数据格式Object { key:...,title:...,... }
            onDrop={onDrop} //拖拽结束后触发的回调函数
            onSelect={onSelect} // 选中某一级的回调函数
        />
    </>
}

  

2. 第二个拖放组件 react-beautiful-dnd

这个拖拽组件用于列表拖拽,只可以水平,垂直拖拽.拖拽的UI非常不错, 可以动态增删列表

react-beautiful-dnd拖拽图片

import React,useState } from "react"
import { DragDropContext,Droppable,Draggable } from "react-beautiful-dnd";

//每一项的样式
const getItemStyle = () => ({
    background: "white",height: 50,border: "1px solid red",width: "100%",margin: "0 0 20px 0"
})

// 重新记录数组顺序
const reorder = (list,startIndex,endIndex) => {
    const result = Array.from(list);
    //删除并记录 删除元素
    const [removed] = result.splice(startIndex,1);
    //将原来的元素添加进数组
    result.splice(endIndex,removed);
    return result;
};


export default function App() {
    const [data,setData] = useState([])
    useEffect(() => {
        if (data.length === 0) {
            //初始化数据
            const newData = Array.from({ length: 5 },index) => ({ key: "key" + index,content: "item" + index }))
            setData(newData)
        }
    },[data])

    //拖拽结束
    const onDragEnd = (result) => {
        if (!result.destination) {
            return;
        }
        //获取拖拽后的数据 重新赋值
        const newData = reorder(data,result.source.index,result.destination.index)
        setData(newData)
    }
    return <DragDropContext onDragEnd={onDragEnd}>
        {/* direction代表拖拽方向  默认垂直方向  水平方向:horizontal */}
        <Droppable droppableId="droppable">
            {(provided,snapshot) => (
                //这里是拖拽容器 在这里设置容器的宽高等等...
                <div
                    {...provided.droppableProps}
                    ref={provided.innerRef}
                    style={{
                        width: 800,padding: 10
                    }}
                >
                    {/* 这里放置所需要拖拽的组件,必须要被 Draggable 包裹 */}
                    {
                        data.map((item,index) => (
                            <Draggable
                                index={index}
                                key={item.key}
                                draggableId={item.key}
                            >
                                {(provided,snapshot) => (
                                    //在这里写你的拖拽组件的样式 dom 等等...
                                    <div
                                        ref={provided.innerRef}
                                        {...provided.draggableProps}
                                        {...provided.dragHandleProps}
                                        style={{ ...getItemStyle(),...provided.draggableProps.style }}
                                    >
                                        {item.content}
                                    </div>
                                )}

                            </Draggable>
                        ))
                    }
                    {/* 这个不能少 */}
                    {provided.placeholder}
                </div>
            )}
        </Droppable>
    </DragDropContext>
}

  

3.第三个拖拽组件 react-draggable-tags

一个轻量级的拖拽排序组件。该组件封装了一系列拖拽功能,可以灵活使用,也未提供任何样式,完全由你来控制(不一定是“tag”,你可以放入任意组件来拖拽排序)。支持移动端。

react-draggable-tags拖拽图片

import React,useState } from "react";
import { DraggableArea } from 'react-draggable-tags';


export default function App() {
    const [data,setData] = useState([])
    useEffect(() => {
        if (data.length === 0) {
            setData([
                { id: 1,content: 'apple' },{ id: 2,content: 'olive' },{ id: 3,content: 'banana' },{ id: 4,content: 'lemon' },{ id: 5,content: 'orange' },{ id: 6,content: 'grape' },{ id: 7,content: 'strawberry' },{ id: 8,content: 'cherry' },{ id: 9,content: 'peach' }
            ])
        }
    },[data])
    //拖拽结束后触发的函数,返回已经改变的data
    const onChange = (tags) => {
        console.log(tags);
    }
    //渲染每项
    const itemRender = ({ tag,index }) => {
        return <div className="tag">
            {tag.content}
        </div>
    }
    return <div className="Simple">
        <DraggableArea
            tags={data}
            render={itemRender}
            onChange={onChange}
        />
    </div>
}

  

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom