カードの 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>
リストが空のときに方法がわかりません。カードをそこにドロップできません。