1

我正在尝试在 react-virtualized 中设置 react-dnd 可排序列表List。我正在使用 react-dnd 的示例在这里:

https://react-dnd.github.io/react-dnd/examples-sortable-simple.html

我已经让它大部分工作了,但是当我拖动一个项目时,我悬停的项目不会调整它们的不透明度并正确重新排序。

在此处输入图像描述

将其与 react-dnd 中的示例进行比较:在此处输入图像描述

我制作了一个示例项目来演示该问题(https://github.com/ericdcobb/virtual-drag-n-drop),但会将代码粘贴到此处。这是 DragDropContext:

import React, {Component} from 'react';
import './App.css';
import {List} from 'react-virtualized';
import {name} from 'faker';
import Item from './Item.js';
import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import update from 'react/lib/update';

class App extends Component {
    constructor(props) {
        super(props);

        const items = [];

        for (let i = 0; i < 1000; i += 1) {
            const item = {
                id: i,
                text: name.findName()
            };
            items[i] = item;
        }

        this.state = {
            items: items
        }
        this.rowRenderer = this.rowRenderer.bind(this);
        this.moveItem = this.moveItem.bind(this);
    }

    moveItem(dragIndex, hoverIndex) {
        const {items} = this.state;
        const dragItem = items[dragIndex];
        this.setState(update(this.state, {
            items: {
                $splice: [
                    [
                        dragIndex, 1
                    ],
                    [hoverIndex, 0, dragItem]
                ]
            }
        }));
    }

    rowRenderer(row) {
        const {items} = this.state;
        const item = items[row.index]

        return (<Item index={row.index} key={row.key} style={row.style} item={item} moveItem={this.moveItem}/>);
    }

    render() {
        const {items} = this.state;
        return (
            <div className="App">
                <List className="list-group" width={800} items={items} height={1000} rowCount={items.length} rowHeight={55} rowRenderer={this.rowRenderer}/>
            </div>
        );
    }
}

export default DragDropContext(HTML5Backend)(App);

和 DragSource/DragTarget:

import React, {Component} from 'react';
import {DragSource, DropTarget} from 'react-dnd';
import { findDOMNode } from 'react-dom';
import _ from 'lodash';

const ItemSource = {
    beginDrag(props) {
        return {id: props.item.id,
        index: props.index};
    }
};

const ItemTarget = {
    hover(props, monitor, component) {
        const dragIndex = monitor.getItem().index;
        const hoverIndex = props.index;

        // Don't replace items with themselves
        if (dragIndex === hoverIndex) {
            return;
        }

        // Determine rectangle on screen
        const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();

        // Get vertical middle
        const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

        // Determine mouse position
        const clientOffset = monitor.getClientOffset();

        // Get pixels to the top
        const hoverClientY = clientOffset.y - hoverBoundingRect.top;

        // Only perform the move when the mouse has crossed half of the items height
        // When dragging downwards, only move when the cursor is below 50%
        // When dragging upwards, only move when the cursor is above 50%

        // Dragging downwards
        if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
            return;
        }

        // Dragging upwards
        if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
            return;
        }

        // Time to actually perform the action
        props.moveItem(dragIndex, hoverIndex);

        // Note: we're mutating the monitor item here!
        // Generally it's better to avoid mutations,
        // but it's good here for the sake of performance
        // to avoid expensive index searches.
        monitor.getItem().index = hoverIndex;
    }
};

function collect(connect, monitor) {
    return {connectDragSource: connect.dragSource(), isDragging: monitor.isDragging()}
}

function connect(connect, monitor) {
    return {connectDropTarget: connect.dropTarget()}
}

class Item extends Component {

    render() {
        let self = this;
        const {connectDragSource, isDragging, connectDropTarget, style} = self.props;

        const opacity = isDragging
            ? 0
            : 1;

        return connectDragSource(connectDropTarget(
            <div key={self.props.key} style={{...style, opacity}} className="Item">
                <div className="row">
                    <div className="col-md-10">{self.props.item.text}</div>

                </div>
            </div>
        ));
    }
}

//TODO constant for this first string
export default _.flow([
    DragSource('item', ItemSource, collect),
    DropTarget('item', ItemTarget, connect)
])(Item);

我试图让项目在拖动的项目周围流动,就像在示例中所做的那样。似乎在我的实现中,错误的项目变得不透明,并且无法向上或向下移动。

抱歉这里有些含糊不清,我想在屏幕上拖放东西很难说,希望代码和屏幕截图有助于解释我的问题。

谢谢!

4

1 回答 1

0

我知道这个超级稍后会回复,但我发现有些人在创建 DnD 列表时可能会遇到这个问题

为了使这项工作正常工作,您需要传递iditem(或card- 这取决于您如何命名您的项目)

所以你必须做这样的事情:

<DndCard
  id={item.id}
  key={item.id}
  state={hiddenColumnState}
  dispatch={hiddenDispatch}
  index={index}
  canDrag={!locked.includes(item)}
>
  {i18n.t(`UI.${item}`)}
  {isLocked(item)}
</DndCard>

注意:不要使用 index 作为键,因为它无法判断 item 是否为 uniq。

最终,您要将 id 放入拖动中:

  const [ dragProps, connectDrag ] = useDrag({
    item: {
      id, // magic is here
      type: state.type,
      index,
      items: state.items,
      indexMemo: index,
      item: state.items[ index ],
    },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  });

有关更多信息,您可以参考react-dnd 此处制作的官方示例

于 2021-03-24T18:02:29.673 回答