反应动态、可排序和可拖动的网格

End*_*der 5 javascript grid draggable jquery-ui-sortable reactjs

我有一个 React with JS ES6 的任务,过去两周我一直在努力完成它。示例和代码在这篇文章的底部。

我的目标是制作一个“动态可排序的网格”。

我在这里阅读了一些材料,在谷歌上搜索并尝试了React Sortable (HOC)react-sortablejsReact Sortable等库。我试图重写一个库,但没有成功。

在这种情况下您会使用哪个库,或者您可以建议我在这种情况下做什么?

在输入中,我有一个来自 API 的 JSON,如下所示:

{
    "items":[
        {
            "sub_items":[
                {
                    "id":1,
                    "name":"Item 1"
                }
            ],
            "type":"Type 1"
        },
        {
            "sub_items":[
                {
                    "id":2,
                    "name":"Item 2"
                },
                {
                    "id":3,
                    "name":"Item 3"
                }
            ],
            "type":"Type 2"
        },
        {
            "sub_items":[
                {
                    "id":4,
                    "name":"Item 4"
                }
            ],
            "type":"Type 3"
        },
        {
            "sub_items":[
                {
                    "id":5,
                    "name":"Item 5"
                },
                {
                    "id":6,
                    "name":"Item 6"
                },
                {
                    "id":7,
                    "name":"Item 7"
                }
            ],
            "type":"Type 4"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

JSON 保存在 React 状态中,然后在render()方法内部访问。

我的代码:

索引.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

Run Code Online (Sandbox Code Playgroud)

应用程序.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// import { SortableItem, swapArrayPositions } from 'react-sort-list';
// import {SortableContainer, SortableElement} from 'react-sortable-hoc';

import { Container, Row, Col, Form, Nav, NavItem } from 'reactstrap';
import NewItem from "./NewItem";
import './App.css';

class App extends Component {
    constructor(props){
        super(props);
        this.state = {
            draggable: true,
            items: [
                {
                    "sub_items": [
                        {
                            "id": 1,
                            "name": "Item 1"
                        }
                    ],
                    "type": "Type 1"
                },
                {
                    "sub_items": [
                        {
                            "id": 2,
                            "name": "Item 2"
                        },
                        {
                            "id": 3,
                            "name": "Item 3"
                        }
                    ],
                    "type": "Type 2"
                },
                {
                    "sub_items": [
                        {
                            "id": 4,
                            "name": "Item 4"
                        }
                    ],
                    "type": "Type 3"
                },
                {
                    "sub_items": [
                        {
                            "id": 5,
                            "name": "Item 5"
                        },
                        {
                            "id": 6,
                            "name": "Item 6"
                        },
                        {
                            "id": 7,
                            "name": "Item 7"
                        }
                    ],
                    "type": "Type 4"
                }
            ]
        }
    }


    dragStart( event ){
        var c = event.target.closest(".td");
        var p = c.closest(".tr");

        event.dataTransfer.setData("text", c.id);
        c.style.width = "150px";
        if ( p.children.length !== 3 ){
            p.classList.remove("full_row")
        }
    }

    dragEnter(event){
    }

    dragEnd(event){
        var data = event.dataTransfer.getData("text");
        var p = document.getElementById(data);

        var p = event.target.closest(".tr");
        if ( p.children.length === 0 ){
            try{
                p.remove();
            }catch( err ){
                console.log( err )
            }
        }else if ( p.children.length === 1 ){
            p.classList.remove("full_row")
        }else if ( p.children.length === 2 ){
            p.classList.remove("full_row")
            for ( var i=0, item; item=p.children[i]; i++ ){
                item.classList.remove("row_1");
                item.classList.remove("row_3");
                item.classList.add("row_2");
            }
        }else if ( p.children.length === 3 ){
            for ( var i=0, item; item=p.children[i]; i++ ){
                item.classList.remove("row_1");
                item.classList.remove("row_2");
                item.classList.add("row_3");
            }
        }
        event.target.style.width = null;

        var empty_table_rows = document.getElementsByClassName("tr");
        for (var i=0, item; item=empty_table_rows[i]; i++ ){
            if ( item.children.length === 0 ){
                try{
                    item.remove();
                }catch( err ){
                    console.log( err );
                }
            }else{
                switch ( item.children.length ){
                    case 1:
                        item.children[0].classList.remove("row_3");
                        item.children[0].classList.remove("row_2");
                        item.children[0].classList.add("row_1");
                        break;
                    case 2:
                        for (var j=0, child; child=item.children[j]; j++ ){
                            child.classList.remove("row_1");
                            child.classList.remove("row_3");
                            child.classList.add("row_2");
                        }
                        break;
                    case 3:
                        for (var j=0, child; child=item.children[j]; j++ ){
                            child.classList.remove("row_1");
                            child.classList.remove("row_2");
                            child.classList.add("row_3");
                        }
                        break;
                }
            }
        }


        var new_rows = document.getElementsByClassName("tr_for_drop");
        for ( var i=0; i < new_rows.length; i++ ){
            if ( new_rows[i].children.length === 1 || new_rows[i].children.length === 0 ){
                new_rows[i].remove();
            }
        }

        var new_items = document.getElementsByClassName("new_item");
        for ( var i=0; i < new_items.length; i++ ){
            var k = new_itms[i].parentNode;
            var m = k.closest(".tr");
            k.remove();
            if ( m.children.length === 0 ){
                m.remove();
            }
        }
    }

    dragOver( event ){
        event.preventDefault();
        event.target.closest(".td").classList.remove("row_1");
        event.target.closest(".td").classList.remove("row_2");
        event.target.closest(".td").classList.add("row_3");
    }

    tableRowDragOver( event ){
        var _this = this;
        console.log("TABLE ROW DRAG OVER")
        var table_row = event.target.closest(".tr");
        var child_number = table_row.children.length;
        console.log(child_number);
        switch( child_number ){
            case 1:
                var d = document.createElement("div");
                ReactDOM.render(<NewItem
                    draggable={ _this.state.draggable }
                    dragStart={ _this.dragStart.bind( _this ) }
                    dragEnd={ _this.dragEnd.bind( _this ) }
                    dragOver={ _this.dragOver.bind( _this ) }
                    dragEnter={ _this.dragEnter.bind( _this ) }
                />, d)
                table_row.appendChild(d)
        }
    }

    drop( event ){
        var trigger = event.target.closest(".tr").classList.contains("full_row");
        if ( trigger ){
            event.preventDefault();
            return 0;
        }else{
            event.preventDefault();
            var data = event.dataTransfer.getData("text");
            var t = document.getElementById( data );
            var p = event.target.closest(".tr");
            p.appendChild(t);
            if (p.children.length === 3){
                p.classList.add("full_row")
                for ( var i=0, item; item=p.children[i]; i++ ){
                    item.classList.remove("row_1");
                    item.classList.remove("row_2");
                    item.classList.add("row_3");
                }
            }else if ( p.children.length === 2 ){
                for ( var i=0, item; item=p.children[i]; i++ ){
                    item.classList.remove("row_1");
                    item.classList.remove("row_3");
                    item.classList.add("row_2");
                }
            }
        }

        var empty_table_rows = document.getElementsByClassName("tr");
        for (var i=0, item; item=empty_table_rows[i]; i++ ){
            if ( item.children.length === 0 ){
                try{
                    item.remove()
                }catch( err ){
                    console.log( err )
                }
            }else{
                switch ( item.children.length ){
                    case 1:
                        item.children[0].classList.remove("row_3");
                        item.children[0].classList.remove("row_2");
                        item.children[0].classList.add("row_1");
                        break;
                    case 2:
                        for (var j=0, child; child=item.children[j]; j++ ){
                            child.classList.remove("row_1");
                            child.classList.remove("row_3");
                            child.classList.add("row_2");
                        }
                        break;
                    case 3:
                        for (var j=0, child; child=item.children[j]; j++ ){
                            child.classList.remove("row_1");
                            child.classList.remove("row_2");
                            child.classList.add("row_3");
                        }
                        break;
                }
            }
        }

        var new_rows = document.getElementsByClassName("tr_for_drop");
        for ( var i=0; i < new_rows.length; i++ ){
            if ( new_rows[i].children.length === 1 || new_rows[i].children.length === 0 ){
                new_rows[i].remove();
            }
        }

        var new_items = document.getElementsByClassName("new_item");
        for ( var i=0; i < new_items.length; i++ ){
            var item = new_items[i];
            var ch = item.closest(".tr_for_drop").children;
            console.log(item.closest(".tr_for_drop"))
            if ( ch.length === 1 ){
                // item.closest(".tr_for_drop").remove();
            }else{
                item.closest(".tr_for_drop").classList.add("real_row");
                item.closest(".tr_for_drop").classList.remove("tr_for_drop");
                item.remove();
            }
        }
        return false;
    }

    render() {
        const Items = (data) => {
            console.log(data.items.length)
            switch (data.items.length) {
                case 1:
                    return (
                        <div onDragOver={this.tableRowDragOver.bind(this)}
                                onDrop={this.drop.bind(this)}
                                className="tr real_row">
                            {
                                data.items.map((item, item_index) => {
                                    return (
                                        <div key={item_index}
                                                onDragStart={this.dragStart.bind(this)}
                                                onDragEnd={this.dragEnd.bind(this)}
                                                onDragOver={this.dragOver.bind(this)}
                                                onDragEnter={this.dragEnter.bind(this)}
                                                draggable={this.state.draggable}
                                                id={"item" + item.id}
                                                className="disable_select td real_item item_cell row_1 ui-sortable itemParent"
                                                data-name={item.name}
                                                data-parent-row="1"
                                                data-col={item_index + 1}>

                                            <div className="command_navigate" style={{
                                                opacity: "0.5",
                                                position: "absolute",
                                                transform: "rotateZ(90deg)",
                                                left: "10px",
                                                top: "10px"
                                            }}>
                                                <i className="ion-ios-more"/>
                                                <i style={{marginTop: "-5px", position: "absolute", left: "0"}}
                                                    className="ion-ios-more"/>
                                            </div>
                                            <div data-type="draft_item" className="item_container disable_select">
                                                {item.name}
                                            </div>
                                        </div>
                                    )
                                })
                            }
                        </div>
                    );
                case 2:
                    return (
                        <div onDragOver={this.tableRowDragOver.bind(this)}
                                onDrop={this.drop.bind(this)}
                                className="tr real_row">
                            {
                                data.items.map((item, item_index) => {
                                    return (
                                        <div key={item_index}
                                                onDragStart={this.dragStart.bind(this)}
                                                onDragEnd={this.dragEnd.bind(this)}
                                                onDragOver={this.dragOver.bind(this)}
                                                onDragEnter={this.dragEnter.bind(this)}
                                                draggable={this.state.draggable}
                                                id={"item_" + item.id}
                                                className="disable_select td real_item item_cell row_2 ui-sortable itemParent"
                                                data-id={item.id}
                                                data-name={item.name}
                                                data-col={item_index + 1}>

                                            <div className="item_navigate" style={{
                                                opacity: "0.5",
                                                position: "absolute",
                                                transform: "rotateZ(90deg)",
                                                left: "10px",
                                                top: "10px"
                                            }}>
                                                <i className="ion-ios-more"/>
                                                <i style={{marginTop: "-5px", position: "absolute", left: "0"}}
                                                    className="ion-ios-more"/>
                                            </div>
                                            <div data-type="draft_item" className="item_container">
                                                {item.name}
                                            </div>
                                        </div>
                                    )
                                })
                            }
                        </div>
                    );
                case 3:
                    return (
                        <div onDragOver={this.tableRowDragOver.bind(this)}
                                onDrop={this.drop.bind(this)}
                                className="tr real_row full_row">
                            {
                                data.items.map((item, item_index) => {
                                    return (
                                        <div key={item_index}
                                                onDragStart={this.dragStart.bind(this)}
                                                onDragEnd={this.dragEnd.bind(this)}
                                                onDragOver={this.dragOver.bind(this)}
                                                onDragEnter={this.dragEnter.bind(this)}
                                                draggable={this.state.draggable}
                                                id={"item_" + item.id}
                                                className="disable_select td real_item item_cell row_3 ui-sortable itemParent"                                             data-id={item.id}
                                                data-name={item.name}
                                                data-parent-row="1"
                                                data-col={item_index + 1}>

                                            <div className="item_navigate" style={{
                                                opacity: "0.5",
                                                position: "absolute",
                                                transform: "rotateZ(90deg)",
                                                left: "10px",
                                                top: "10px"
                                            }}>
                                                <i className="ion-ios-more"/>
                                                <i style={{marginTop: "-5px", position: "absolute", left: "0"}}
                                                    className="ion-ios-more"/>
                                            </div>
                                            <div data-type="draft_item" className="item_container">
                                                {item.name}
                                            </div>
                                        </div>
                                    )
                                })
                            }
                        </div>
                    )
            }
        };

        return (
            <div>
                <div className="table ui-sortable">
                    <div className="tbody">
                        {
                            this.state.items.map((item, index) => {
                                return (