I'm trying to build a react nested list component that is fully draggable with react-dnd.(我正在尝试构建一个可与react-dnd完全拖动的react嵌套列表组件。)
I have a menu component which contains item components, and each item can also contain other item components.(我有一个包含项目组件的菜单组件,每个项目也可以包含其他项目组件。) Unfortunately I don't know how to make a node with children draggable or any of its children nodes.(不幸的是,我不知道如何使带有子级的节点或其任何子级节点可拖动。) Right now I have gotten nodes without childrendraggable, which is a good start, but then fails with:(现在,我的节点没有可拖拽的子节点,这是一个不错的开始,但是失败了:)
TypeError: node is undefined(TypeError:节点未定义)
any time I try to drag any children.(每当我尝试拖拽任何孩子时。)
I used the react-dnd simple sortable example as a reference, but that doesn't contain any nesting.(我使用了react-dnd 简单可排序示例作为参考,但是其中不包含任何嵌套。)
Here is what I have so far:(这是我到目前为止的内容:)
Menu.js(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(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));
It seems as though the nested items are not being passed dragSource and dropTarget correctly because they are not wrapped when I look at the structure in my React DevTools browser extension, but I'm not sure because I feel react-dnd should take care of that.(似乎嵌套项没有正确传递给dragSource和dropTarget,因为当我在React DevTools浏览器扩展中查看结构时,它们没有被包装,但是我不确定,因为我觉得react-dnd应该解决这个问题。)
Thanks in advance, any guidance will be greatly appreciated.(在此先感谢您的指导。)
ask by BDUB translate from so
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…