【发布时间】:2015-11-11 20:24:46
【问题描述】:
我正在尝试构建一个可以使用 react-dnd 完全拖动的反应嵌套列表组件。我有一个包含项目组件的菜单组件,每个项目还可以包含其他项目组件。不幸的是,我不知道如何使具有可拖动子节点的节点或其任何子节点。现在我得到了没有 childrendraggable 的节点,这是一个好的开始,但随后失败了:
TypeError: 节点未定义
任何时候我试图拖动任何孩子。我使用了 react-dnd simple sortable 示例作为参考,但它不包含任何嵌套。
这是我目前所拥有的:
Menu.js
//React DnD
var DragDropContext = require('react-dnd').DragDropContext;
var HTML5Backend = require('react-dnd-html5-backend');
//Item
var Item = require('./item');
var Menu = React.createClass({
getInitialState() {
return {
currentNode: this.props.data,
items: [],
};
},
_clicked(child) {
this.setState({
currentNode: child,
});
},
componentDidMount() {
this._updateData();
},
_updateData: function(list) {
var $this = this;
if(_.isUndefined(list)){
var children = $this.props.data.children;
}
else{
if(_.isEmpty(list.children)){
var children = null;
}
else{
var children = list.children;
}
}
if(children != null){
var items = children.map(function(item, i) {
return (<Item
key={item.id}
id={item.id}
child={item}
showChildren={this.props.showFirstChildren}
clickable={true}
onClick={$this._updateData}
swapItems={this.swapItems}
/>);
}.bind(this));
if(!_.isUndefined(list)){
$this.setState({
currentNode: list,
});
}
$this.setState({
items: items,
});
}
},
compareItems: function(item1, item2){
return item1.position - item2.position;
},
swapItems: function(id1, id2) {
var $this = this;
var items = this.state.currentNode.children;
var item1 = items.filter(function(i){return i.id === id1})[0];
var item2 = items.filter(function(i){return i.id === id2})[0];
var item1Pos = item1.position;
item1.position = item2.position;
item2.position = item1Pos;
items.sort(this.compareItems);
var newItems = items.map(function(item, i) {
return (<Item
key={item.id}
id={item.id}
child={item}
showChildren={this.props.showFirstChildren}
clickable={true}
onClick={$this._updateData}
swapItems={this.swapItems}
/>);
}.bind(this));
this.setState({
items: newItems,
});
},
render() {
return (
<div>
{this.state.currentNode.name}
<ul>
{this.state.items}
</ul>
</div>
);
},
});
module.exports = DragDropContext(HTML5Backend)(Menu);
Item.js
var React = require('react');
var ReactDnD = require('react-dnd');
var ItemTypes = {
ITEM: 'item'
};
var itemSource = {
beginDrag: function (props) {
return {
id: props.id,
};
}
};
var itemTarget = {
hover: function(props, monitor) {
var draggedId = monitor.getItem().id;
if (draggedId !== props.id) {
props.swapItems(draggedId, props.id);
}
}
};
var Item = React.createClass({
propTypes: {
connectDropTarget: React.PropTypes.func,
connectDragSource: React.PropTypes.func,
isDragging: React.PropTypes.bool,
id: React.PropTypes.any,
swapItems: React.PropTypes.func,
},
_clicked(child) {
this.props.onClick(child);
},
render() {
var $this = this;
var connectDragSource = $this.props.connectDragSource;
var isDragging = $this.props.isDragging;
var connectDropTarget = $this.props.connectDropTarget;
var child = this.props.child;
var childrenWrapper = null;
if (child.children && this.props.showChildren) {
var children = child.children.map(function(item, i) {
return (<Item
key={item.id}
id={item.id}
showChildren={false}
child={item}
onClick={$this._clicked}
clickable={true}
//passing these items along because otherwise it throws errors
connectDropTarget={$this.props.connectDropTarget}
connectDragSource={$this.props.connectDragSource}
swapItems={$this.props.swapItems}
/>);
});
childrenWrapper = (
<ul>
{children}
</ul>
);
}
var style = {
cursor: 'move',
opacity: this.props.isDragging ? 0 : 1
};
if (child.children && this.props.clickable) {
return connectDragSource(connectDropTarget(
<li style={style} key={child.id} ><a onClick={$this._clicked.bind(null, child)}>{child.title}</a>{childrenWrapper}</li>
));
} else {
return connectDragSource(connectDropTarget(
<li style={style} key={child.id}><a>{child.title}{childrenWrapper}</a></li>
));
}
},
});
var DragSourceDecorator = ReactDnD.DragSource(ItemTypes.ITEM, itemSource,
function(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
};
});
var DropTargetDecorator = ReactDnD.DropTarget(ItemTypes.ITEM, itemTarget,
function(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
};
});
module.exports = DropTargetDecorator(DragSourceDecorator(Item));
似乎嵌套项目没有正确传递 dragSource 和 dropTarget 因为当我查看我的 React DevTools 浏览器扩展中的结构时它们没有被包装,但我不确定因为我觉得 react-dnd 应该采取关心那个。在此先感谢,任何指导将不胜感激。
【问题讨论】:
-
无耻插件,但我为这个用例使用 react-dnd 制作了react-sortable-tree。
标签: javascript reactjs nested-lists