Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
577 views
in Technique[技术] by (71.8m points)

javascript - React-dnd-不知道如何拖放相同类型的嵌套组件(React-dnd - Not sure how to get drag and drop to fire for nested components of the same type)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I've got the same problem when I try to manipulate tree before drag end.(当我尝试在拖尾之前操纵树时,我遇到了同样的问题。)

Ie change leafs order before dragEnd() throw me the same error.(即在dragEnd()抛出相同错误之前更改叶子顺序。) But plain list works perfectly.(但是简单列表很完美。) I stop to change tree during DnD (our designer said - it is not good UX: jumping to mouse pointer subtree).(我在DnD期间停止更改树(我们的设计师说过-不好的UX:跳转到鼠标指针子树)。) So my solution: during DnD just change classes for target and source sub-trees (but do not change leafs order), like:(所以我的解决方案是:在DnD期间只需更改目标和源子树的类(但不更改叶子顺序),例如:)
  .source-dnd {
    opacity: 0.2;
  }

  .target-dnd-add {
    border: 1px dotted #aaa;
  }

  .target-dnd-after {
    border-bottom: 1px dotted #aaa;
  }

  .target-dnd-before {
    border-top: 1px dotted #aaa;
  }

Also don't forget about monitor.isOver({ shallow: true })(也不要忘了monitor.isOver({ shallow: true }))


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...