React dnd-不确定如何为相同类型的嵌套组件启用拖放
React-dnd - Not sure how to get drag and drop to fire for nested components of the same type
我正在尝试构建一个可使用react dnd完全拖动的react嵌套列表组件。我有一个包含项目组件的菜单组件,每个项目也可以包含其他项目组件。不幸的是,我不知道如何使具有子节点或其任何子节点的节点可拖动。现在我已经得到了没有childrendraggable的节点,这是一个很好的开始,但后来失败了:
类型错误:节点未定义
每当我试图拖着任何孩子的时候。我使用了react dnd简单可排序示例作为参考,但它不包含任何嵌套。
以下是我目前所拥有的:
菜单.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应该处理好这一点。提前感谢,如有任何指导,我们将不胜感激。
您不必将"connectDropTarget"answers"connectDropTarget"传递到嵌套项。相反,你必须包装内项目的渲染方法,而不是
return (<Item
key={item.id}...
写入
return (<WrappedItem
key={item.id}…
而不是
module.exports = DropTargetDecorator(DragSourceDecorator(Item));
写入
var WrappedItem = DropTargetDecorator(DragSourceDecorator(Item));
module.exports = WrappedItem;
当我试图在拖动结束前操作树时,也遇到了同样的问题。也就是说,在dragEnd()之前更改叶子的顺序会给我同样的错误。但简单列表非常有效。我在DnD期间停下来更改树(我们的设计师说——这不是好的UX:跳到鼠标指针子树)。所以我的解决方案是:在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;
}
也不要忘记monitor.isOver({ shallow: true })
相关文章:
- 在嵌套组件中使用 react 组件时模块中断
- 在 React 中嵌套组件,props 不会传递给子组件
- 反应:在嵌套组件上冒泡点击事件
- Angular 1.5 嵌套组件绑定父值
- 在 knockoutjs 中嵌套组件
- 您如何处理 Angular2 中嵌套组件的依赖关系
- 如何处理 React 嵌套组件循环依赖?(使用 es6 类)
- AngularJS通过嵌套组件向上传播更改
- 如何在 RivetsJS 中处理递归嵌套组件
- 了解嵌套组件绑定在 KnockoutJS 上的工作原理
- 聚合物.js嵌套组件中的数据绑定
- 如何以正确的方式嵌套组件
- 映射到嵌套组件的 Elm 效果
- Material-ui:如何在嵌套组件中停止单击事件的传播
- 使用键来识别 React.js 中的嵌套组件
- Angular2 嵌套组件: 错误: core_2.输入不是函数 加载 http://localhost:9080/ap
- 如何将全局状态数据处理到Redux中的深度嵌套组件中
- React dnd-不确定如何为相同类型的嵌套组件启用拖放
- React Router-在嵌套组件中安装组件
- Uikit.可嵌套组件-如何从移动的项目获取id