0

我有一个 html 列表,我交换了列表项(reactjs 状态)。交换项目后,如果我在两者之间删除项目(实际上我在状态下正确删除项目但无法在列表中正确显示),我该如何重新呈现列表项目?

状态:项目是一个数组。数组位置可以与每个项目位置状态值不同(参见对象)。

列表:列表位置是每个项目的位置,即对象值,但与对象的数组索引相比可以不同。

交换项:通过拖放更改涉及的每个列表项的内部html。

擦除:当我擦除介于两者之间的最近交换的项目时,它会擦除​​最后一个列表项,尽管它不包括被删除的数组状态的项目(数组状态的变化很好,只是图形界面显示了问题) .

我的状态:

this.state = {
            items:[{item:"", position: 0}],
            type: "text"
        };

我通过更改每个列表项的内部 HTML 来交换项目时的 Drop 功能:

drop(event) {
        event.preventDefault();
        let dropId = event.target.id;
        let data = event.dataTransfer.getData("text");
        if(data != dropId){

            //  Changing list items positions
            let dropSpace = document.getElementById(dropId);
            let dataSpace = document.getElementById(data);
            if (dropSpace === null){
                console.log("wrong zone");
                return -1;
            }
            dropSpace.classList.remove('over');
            let auxInner = dropSpace.innerHTML;
            console.log(dropSpace);
            console.log(dataSpace);
            console.log(auxInner);
            dropSpace.innerHTML = dataSpace.innerHTML;
            dataSpace.innerHTML = auxInner;

            // dropSpace.setAttribute("id", data);
            // dataSpace.setAttribute("id", dropId);

            //  Position update
            let idx = parseInt(data.substr(data.length - 1));
            let position = parseInt(dropId.substr(dropId.length - 1));
            let iArray = this.state.items;

            iArray[iArray.findIndex(item => item.position === idx)].position = position;
            iArray[iArray.findIndex(item => item.position === position)].position = idx;
            // iArray[idx].position = position;
            // iArray[position].position = idx;
            console.log(iArray);

            //  Restaurating the events
            let but1 = document.getElementById("erase"+idx);
            but1.addEventListener("click", this.eraseItem);
            let but2 = document.getElementById("erase"+position);
            but2.addEventListener("click", this.eraseItem);

            this.setState({
                items: iArray
            });
        }

        //  Avoid changing the type of input (anti-fail system :) )
        let typeElement = document.getElementById("item-type");
        typeElement.disabled = true;
    }

我的擦除功能:

eraseItem(event){
        let targetId = event.target.id;
        // let element = document.getElementById(targetId);
        // let parent = element.parentNode;
        // parent.innerHTML = "";
        // console.log(targetId);
        let idx = parseInt(targetId.substr(targetId.length - 1));
        let iArray = this.state.items;
        // iArray.splice(iArray.findIndex(item => item.position === idx), 1);
        let erasen = iArray.splice(idx, 1);
        iArray.map((item) =>{
            if(item.position >= erasen[0].position){
                let pos = item.position;
                item.position = pos - 1;
            }
        });
        console.log(erasen[0]);
        console.log(iArray);
        this.setState({
            items: iArray
        });
    }

当我使用这些功能和状态作为道具时,我的反应组件的内容:

<ul id="item-zone"
                    className="ul-items">
                    {
                        this.props.items.map((item, idx)=> {
                            return (
                                <li id={"container"+idx}
                                    onDragStart={this.props.drag}
                                    onDrop={this.props.drop}
                                    onDragOver={this.props.allowDrop}
                                    onDragEnter={this.props.dragEnter}
                                    onDragLeave={this.props.dragLeave}
                                    className="dad"
                                    draggable="true"
                                    key={idx}>
                                    <Button className={"questionErase set-left showErase"}
                                            id={"erase"+idx}
                                            draggable="false"
                                            onClick={this.props.eraseItem} block>
                                        <Glyphicon glyph="trash" id={"erase"+idx} />
                                    </Button>
                                    <div className={this.props.type === "text" ? "showDiv":"hiddenDiv"}
                                         draggable="false">
                                        <FieldGroup
                                            id={'itemText'+idx}
                                            type='text'
                                            name={'itemText'+idx}
                                            className="set-right itemButton"
                                            placeholder='Write Item'
                                            value={item.item}
                                            onChange={this.props.changeField}
                                        />
                                    </div>
                                    <div className={this.props.type === "image" ? "showDiv":"hiddenDiv"}
                                         draggable="false">
                                        <FieldGroup
                                            id={'itemUrl'+idx}
                                            type='url'
                                            name={'itemUrl'+idx}
                                            className="set-right itemButton"
                                            placeholder='Write Item Url'
                                            value={item.item}
                                            onChange={this.props.changeField}
                                        />
                                    </div>
                                </li>
                            )
                        })
                    }
                </ul>

现在的结果:

  • 我正确地交换了项目,但是在交换后擦除中间的项目(例如列表中的位置 2)时,只需擦除最后一个列表项,同时在位置 2 中显示错误信息(对于本示例)。根据开发人员控制台,状态数据很好。
4

1 回答 1

0

今天我可以解决下一个问题:

问题:对 reactjs 状态的错误理解。当更改包含状态的 html 时,不是同时更改数组和列表中项目位置的正确方法。

答:我确实通过“更新”每个列表项的 innerHTML 来交换这些项。因此,您可以避免该过程,而只需更新状态中对象的数组索引,它会自动更改对象/项目在数组以及 GUI(html 中的列表)中的位置。(请参阅代码中注释后的更改:“更新的项目的数组索引”。

注意:不要在使用反应状态时在列表项之间交换 innerHTML 内容,因为在更新/删除该反应状态的项目时会遇到问题。取而代之的是,您应该更改数组状态中的位置,React 将为您在视图中进行更改。

    drop(event) {
        event.preventDefault();
        let dropId = event.target.id;
        let data = event.dataTransfer.getData("text");
        if(data != dropId){

            //  Changing list items positions
            let dropSpace = document.getElementById(dropId);
            dropSpace.classList.remove('over');
            // this.positionUpdate(dropId, data);

            //  Position update
            let idx = parseInt(data.substr(data.length - 1));
            let position = parseInt(dropId.substr(dropId.length - 1));
            let iArray = this.state.items;

            //  Array shifting values utilities (saving indexes)
            let arrayIdx = iArray.findIndex(item => item.position === idx);
            let arrayPosition = iArray.findIndex(item => item.position === position);

            //  Array item position value updating
            iArray[arrayIdx].position = position;
            iArray[arrayPosition].position = idx;

            //  Array index of items updated
            let aux = iArray[arrayPosition];
            iArray[arrayPosition] = iArray[arrayIdx];
            iArray[arrayIdx] = aux;
            console.log(iArray);

            this.setState({
                items: iArray
            });
        }

        //  Avoid changing the type of input (anti-fail system :) )
        let typeElement = document.getElementById("item-type");
        typeElement.disabled = true;
    }

并且问题解决了!

于 2019-04-13T12:12:58.160 回答