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

时间:2017-12-12 19:40:28

标签: javascript reactjs grid jquery-ui-sortable draggable

我有一个React与JS ES6的任务,我在过去两周一直试图完成。示例和代码位于本文的底部。

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

我在这里阅读了一些材料,Google搜索并尝试了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"
        }
    ]
}

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

我的代码:

index.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();

App.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 (
                                    <Items key={ index }
                                                    row={ index + 1 }
                                                    length={ item.length }
                                                    items={ item.sub_items }/>
                                )
                            })
                        }
                    </div>
                </div>
                <div className="row_1 item_creator">
                    Add new item
                </div>
            </div>
        )
    }
}

export default App;

NewItem.js

import React, { Component } from 'react';
import './App.css';


export default class NewItem extends Component{
    render(){
        return(
            <div draggable={ this.props.draggable }
                    onDragStart={ this.props.dragStart }
                    onDragEnd={ this.props.dragEnd }
                    onDragOver={ this.props.dragOver }
                    onDragEnter={ this.props.dragEnter }
                    className="td new_item">

                <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">
                    DROP HERE
                </div>
            </div>
        )
    }
}

App.css

.tr{
    margin: 10px 0;
    width: 100%;
    float: left;
}

.td{
    cursor: pointer;
    position: relative;
    float: left;
    border-radius: 5px;
}

.row_1{
    width: 465px;
}

.item_creator{
    text-align: center;
    float: left;
    width: 465px;
    padding: 10px 0;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
    cursor: pointer;
    border:dashed 1px grey;
}

.row_2{
    float: left;
    width: 230px;
    margin-right: 10px;
}

.row_2:nth-child(2){
    margin-right: 0;
}

.row_3{
    float: left;
    width: 150px !important;
    margin-right: 10px;
    max-height: 40px;
    overflow: hidden;
    white-space: pre-wrap;
    text-overflow: ellipsis;
    line-height: 1.7;
    box-shadow: 0 0 10px -2px rgba(42, 42, 42, 0.3);
}

.row_3:nth-child(3){
    margin-right: 0;
}

.item_container{
    background: #fff;
    padding: 10px 15px;
    border-radius: 5px;
    text-align: center;
    box-shadow: 0 0 10px -2px rgba(42, 42, 42, 0.3);
}

因此它应该如下所示: Result

示例1: Example 1

当我得到第2项并将它放在两个实例之间的行上(在随机行之间,或者当我必须将它放在顶行(在第1行的第一行上)时)。排序后项目3 必须将其宽度更改为块的100%(我将类从_row_3_更改为_row_1_)。 第1项的属性为width: 100%,您可以看到上面的结果。在操作结束时,所有带有标签&#34; DROP HERE&#34;必须删除。

示例2:

Example 2

如果我拖动第4项并尝试删除(将元素拖到另一条线上)它在2行元素的行上,则必须将它们的宽度更改为~50%(_row_2_ class)直到我删除拖动的元素。此线上的所有元素必须为~33%宽度。在操作结束时,所有带有标签&#34; DROP HERE&#34;必须删除。

此外,如果我想从包含3个项目的行中获取项目并将其放在另一行中,则元素必须根据项目的数量更改其大小。

我如何处理行列之间的切换元素(从一行上的一列到另一行上的另一列)?

行至少包含1个元素,最多包含3个元素。 线条数量是动态的,因此是无限的。

0 个答案:

没有答案