1

カードの 2 つのリスト間でドラッグ アンド ドロップできるようにしたい。

単純な並べ替え可能な例に基づいて、カードを使用して 2 つのリストを作成し、それらの間でドラッグ アンド ドロップすることに成功しました。

リストの 1 つが完全に空の場合、何らかの理由でカードをドロップできません。

このスニペットは私の問題を示しています:

const ItemTypes = {
    CARD: 'card'
};

let cardSource = {
    beginDrag: function (props, monitor, component) {
        // Return the data describing the dragged item
        return {
            card: props.card,
            originalList: props.cardList,
            originalIndex: props.findCard(props.card).index,
            targetList: props.cardList // at first target is same as original
        }
    },

    endDrag: function (props, monitor, component) {
        let item = monitor.getItem();
        let dropResult = monitor.getDropResult();
        if (!monitor.didDrop()) {
            props.moveCard(item.card, item.originalIndex);
            if (item.targetList !== item.originalList) {
                item.targetList.removeCard(item.card);
            }
            return;
        }
    }
};

let cardTarget = {
    canDrop: function (props, monitor) {
        return true;
    },

    hover: function (props, monitor) {
        let item = monitor.getItem();

        if (item.targetList !== props.cardList) {
            item.targetList.removeCard(item.card);
            item.targetList = props.cardList;
        }

        if (item.card.id !== props.card.id) {
            let card = props.findCard(props.card);
            props.moveCard(item.card, card.index);
        }
    },

    drop: function (props, monitor, component) {
        return monitor.getItem();
    }
};


class CardElement extends React.Component {
    render() {
        let isDragging = this.props.isDragging;
        let connectDragSource = this.props.connectDragSource;
        let connectDropTarget = this.props.connectDropTarget;
        let opacity = isDragging ? 0 : 1; // Not working as expected

        let elm = <div className="card-item" style={{ opacity: opacity }}> Name: { this.props.card.name } id { this.props.card.id } </div>;
        return connectDragSource(connectDropTarget(elm));
    }
}

CardElement.propTypes = {
    connectDragSource: React.PropTypes.func.isRequired,
    connectDropTarget: React.PropTypes.func.isRequired,
    isDragging: React.PropTypes.bool.isRequired,
    card: React.PropTypes.object.isRequired,
    cardList: React.PropTypes.object.isRequired,
    moveCard: React.PropTypes.func.isRequired,
    findCard: React.PropTypes.func.isRequired
}

let cardDropTarget = ReactDnD.DropTarget(ItemTypes.CARD, cardTarget, function (connect, monitor) {
    return {
        connectDropTarget: connect.dropTarget()
    }
})(CardElement);

let Card = ReactDnD.DragSource(ItemTypes.CARD, cardSource, function (connect, monitor) {
    return {
        connectDragSource: connect.dragSource(),
        isDragging: monitor.isDragging()
    };
})(cardDropTarget);

let cardListTarget = {
    drop: function (props, monitor, component) { 
      // when the list empty the cards not dropping here
    },
    canDrop: function () {
        return true;
    }
};

class ListElement extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            cards: this.props.cards
        };
    }

    moveCard(card, atIndex) {
        let found = this.findCard(card);
        let cards = this.state.cards;

        if (found.card) {
            cards.splice(found.index, 1);
            cards.splice(atIndex, 0, found.card);
        } else {
            cards.splice(atIndex, 0, card);
        }
        this.setState({ cards: cards });
    }

    removeCard(card) {
        let found = this.findCard(card);
        let cards = this.state.cards;
        if (found.card) {
            cards.splice(found.index, 1);
        } else {
            // console.log('Can\'t remove card ' + card.id + ' - can\'t find it');
        }
        this.setState({ cards: cards });
    }

    findCard(card) {
        let index = this.state.cards.indexOf(card);
        if (index >= 0) {
            // console.log('found: card: ' + card + ' with id ' + card.id);
        } else {
            // console.log('didn\'t find card');
            card = null;
        }
        return {
            card: card,
            index: index
        };
    }

    render() {
        let connectDropTarget = this.props.connectDropTarget;

        let cardList = this.state.cards.map(card => {
            return <Card key={ card.id }
                card={ card }
                cardList={ this }
                moveCard={ this.moveCard.bind(this) }
                findCard={ this.findCard.bind(this) }
                />
        });

        return connectDropTarget(<div className="col"> {cardList} </div>);
    }
}

let List = ReactDnD.DropTarget(ItemTypes.CARD, cardListTarget, (connect, monitor) => {
    return {
        connectDropTarget: connect.dropTarget()
    }
})(ListElement);

class AppElement extends React.Component {
    constructor(props) {
        super(props);

        let listA = [
            { name: 'Harry', id: 1 },
            { name: 'Jimmy', id: 2 },
            { name: 'Jane', id: 3 },
            { name: 'Adam', id: 4 },
            { name: 'Judith', id: 5 }
        ]
        let listB = [
            { name: 'Edward', id: 6 },
            { name: 'Ronald', id: 7 },
            { name: 'Irene', id: 8 },
            { name: 'Patrick', id: 9 },
            { name: 'Dorothy', id: 10 }
        ]
        this.state = {
            cards: [listA, listB]
        }
    }
    render() {
        return <div id="warper">
            <List cards={ this.state.cards[0]} />
            <List cards={ this.state.cards[1]} />
        </div>;
    }
}
let App = ReactDnD.DragDropContext(ReactDnDHTML5Backend)(AppElement);

ReactDOM.render(<App/>, document.getElementById('app'));
#warper {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-content: space-between;
  align-items: flex-start;
}
.col {
  width: 400px;
  margin: 5px 31px 0px 0px;
  min-height: 300px;
  border: 2px solid black;
  padding: 9px;
}
.card-item {
  border: 1px dashed gray;
  padding: 0.5rem 1rem;
  margin-bottom: .5rem;
  background-color: white;
  cursor: move;
}
<!DOCTYPE html>
<html>

<head>
  <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script>
  <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script>
  <script src="https://npmcdn.com/react-dnd-html5-backend@2.1.2/dist/ReactDnDHTML5Backend.min.js"></script>
  <script src="https://npmcdn.com/react-dnd@2.1.4/dist/ReactDnD.min.js"></script>
</head>

<body>
  <div id="app"></div>
</body>

</html>

リストが空のときに方法がわかりません。カードをそこにドロップできません。

4

1 に答える 1