在 React js 中打开和关闭递归嵌套列表
Open and Close a recursively nested list in React js
我希望能够使用 React 打开/关闭嵌套列表,以便当您单击父级 li 时,子项会被隐藏?这是我用来创建列表的内容。
列表.js
class List extends React.Component {
render(){
return (
<ul>
{this.props.list.map(function(item){
return (
<li>
<ListItem key={item.id} item={item} />
<List list={item.children} />
</li>
);
})}
</ul>
);
}
列表项.js
class ListItem extends React.Component {
handleCollapse(){
console.log('Open/Close: ' + this.props.item.display_name);
return false;
}
handleFilter(){
console.log('Filter id: ' + this.props.item.id);
return false;
}
render(){
return (
<div>
<a rel="{this.props.item.id}" onClick={this.handleCollapse.bind(this)}>
{this.props.item.display_name}
</a>
<input value="" type="checkbox" onClick={this.handleFilter.bind(this)} />
</div>
)
}
您是否正在尝试模拟手风琴行为?如果是,那么您可以像这样修改代码。使用组件的状态并将其切换为打开和关闭子项。导入(或使用require
)list.js
list-item.js
中,而不是在类List
中创建<List list={item.children} />
,并根据当前ListItem's
状态呈现子项List
。
列表项.js
class ListItem extends React.Component {
//Add this
constructor (){
super(...arguments);
this.state = { showChild:false};
}
handleCollapse(){
console.log('Open/Close: ' + this.props.item.display_name);
//Add this
this.setState({showChild:!this.state.showChild});
return false;
}
handleFilter(){
console.log('Filter id: ' + this.props.item.id);
return false;
}
render(){
let children;
if(this.state.showChild) {
children = (<List list={this.props.item.children} />);
}
return (
<div>
<a rel="{this.props.item.id}" onClick={this.handleCollapse.bind(this)}>
{this.props.item.display_name}
</a>
<input value="" type="checkbox" onClick={this.handleFilter.bind(this)} />
//Add this
{children}
</div>
)
};
}
列表.js
class List extends React.Component {
render(){
//Removed <List .../>, rest is same just other way of doing same stuff
let LI = this.props.list.map( (item) => {
return( <li> <ListItem key={item.id} item={item} /></li>);
}
);
return ( <ul>{LI}</ul>);
}
};
要测试的虚拟数据
var data=[
{
id:"1st of Level 1",
get display_name(){return _name(this.id,this.children)},
children: [
{
id:"1st of Level 1.2",
get display_name(){return _name(this.id,this.children)},
children: [
{
id:"1st of Level 1.2.1",
get display_name(){return _name(this.id,this.children)},
children:[]
}
]
},
{
id:"2nd of Level 1.2",
get display_name(){return _name(this.id,this.children)},
children:[]
}
]
},
{
id:"2nd of Level 1",
get display_name(){return _name(this.id,this.children)},
children:[]
},
{
id:"3rd of Level 1",
get display_name(){return _name(this.id,this.children)},
children:[]
},
{
id:"4th of Level1",
get display_name(){return _name(this.id,this.children)},
children:[]
}
];
function _name(id,child) {
if(child.length>0)
return("I am "+id+" I HAVE CHILDREN");
else {
return("I am "+id+" I DON'T HAVE CHILDREN ");
}
}
ReactDOM.render(<List list={data} />,document.getElementById('root'));
'
递归地执行此操作是解决此问题的好方法。您可以做的是为每个列表项元素提供一个onClick
处理程序。
<li onClick={this._toggleChildrenInit.bind(this, item.id)}>
我不太了解你的身份。但请考虑以下结构:
{id: "0", isOpen: false, children: [
{id: "0.0", isOpen: false, children: [
{id: "0.0.0", isOpen: false, children: null},
{id: "0.0.1", isOpen: false, children: null}
]},
{id: "0.1", isOpen: false, children: null}
]}
每个子项的 id 是前一个父级的 id,加上一个"."和该级别内的顺序数。
然后,您可以使用递归检查具有某个 X id 的所需项是否可以是项的子项,并开始以相同的方式遍历该项。这样,您就不必遍历树中的所有项。
当然,这可能因应用程序而异,但希望它能提供有关如何解决此问题的线索。
点击触发的递归代码如下:
_toggleChildrenInit = (data_id) => {
var result = this._toggleChildren(0, data_id, this.state.listObject);
this.setState({listObject: result});
}
_toggleChildren = (i, data_id, arr) => {
if (i <= arr.length-1) {
if (arr[i].id == data_id && arr[i].children.length > 0) {
arr[i].isOpen = !arr[i].isOpen;
} else {
var newArr = this._toggleChildren(0, data_id, arr[i].children);
arr[i].children = newArr;
if (arr[i].id.charAt(0) != data_id.charAt(0)) {
arr[i].isOpen = false;
}
}
arr = this._toggleChildren(++i, data_id, arr);
}
return arr;
}
编辑 - 替代结构
如果对象如下所示:
{id: "0", isOpen: false, children: [
{id: "1", isOpen: false, children: [
{id: "2", isOpen: false, children: null},
{id: "3", isOpen: false, children: null}
]},
{id: "4", isOpen: false, children: null}
]}
您可以改用它:
_toggleChildrenInit = (data_id) => {
var result = this._toggleChildren(0, data_id, this.state.listObject);
this.setState({listObject: result});
}
_toggleChildren = (i, data_id, arr) => {
if (i <= arr.length-1) {
if (arr[i].id == data_id && arr[i].children.length > 0) {
arr[i].isOpen = !arr[i].isOpen;
} else {
var newArr = this._toggleChildren(0, data_id, arr[i].children);
arr[i].children = newArr;
if (arr[i].id < data_id) {
arr[i].isOpen = false;
}
}
arr = this._toggleChildren(++i, data_id, arr);
}
return arr;
}
相关文章:
- 如何递归地获取嵌套对象中所有子对象的列表
- 具有嵌套对象数组的 Javascript 对象的递归搜索函数
- 在嵌套递归指令中将参数传递给父控制器方法
- 递归 - 将 Javascript Map 转换为嵌套的 JSON 对象
- Javascript 从嵌套的 UL LI 复选框生成递归 JSON 对象
- 递归没有完全遍历具有嵌套对象的对象
- 通过Javascript中的递归迭代映射嵌套JSON
- 在JavaScript中,从一组数组递归地构建一个字典/嵌套对象
- .after()在angularjs(嵌套ng重复递归迭代)中
- 递归地将嵌套xml转换为嵌套html
- 递归嵌套 angularjs 指令
- AngularJS 嵌套的 jQuery UI 具有递归的可存储性
- 如何使用jQuery.map递归修改嵌套对象
- Javascript 递归地排序对象和嵌套对象以及数组
- 在 React js 中打开和关闭递归嵌套列表
- 如何在 RivetsJS 中处理递归嵌套组件
- 递归嵌套私有函数
- 在angularjs中递归嵌套指令
- JavaScript中的递归嵌套属性创建
- ember.js的rest JSON递归嵌套在同一个模型中