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, key, 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, dropKey, item => {
                item.children = item.children || [];
                // where to insert 示例添加到頭部,可以是隨意位置
                item.children.unshift(dragObj);
            });
        } else {
            let ar;
            let i;
            loop(data, dropKey, (item, index, arr) => {
                ar = arr;
                i = index;
            });
            if (dropPosition === -1) {
                ar.splice(i, 0, dragObj);
            } else {
                ar.splice(i + 1, 0, 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, { useEffect, 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, 0, removed);
    return result;
};


export default function App() {
    const [data, setData] = useState([])
    useEffect(() => {
        if (data.length === 0) {
            //初始化數據
            const newData = Array.from({ length: 5 }, (item, 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, { useEffect, 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>
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM