封装Tree遇到的问题和知识点
1.怎么封装?
用数据自己去渲染组件
{
type:"rulename"
children:[
{
type:"condition",
children:[]
},
{
type:"action",
children:[]
}
]
}
//组件遇到type就知道自己用哪个组件!
2.思路
TreeData--------> Tree------------>TreeNode
3.TreeNode的设计
最原始的TreeNode
<div className="treenode">
<div className="title">
<Icon type="arrow-down" size='xs' />
<span>
{renderRoot} //渲染 第一个节点
</span>
</div>
<div className="context">
{renderTreeNode} // 渲染留白区域
</div>
</div>
.treenode{
width:100%;
height:100%;
i{
margin-right: 5px !important;
line-height: inherit;
}
span{
width:200px;
line-height: 23px;
}
}
4.TreeNode的递归
思路:每一层只管自己的数据,如自己当前一层的type,key,value
TreeData: {
type: 'rulename',
key: '0',
value: '',
children: [
{
type:'ruleConditions',
key: '0-0',
value: '条件'
},
{
type: 'action',
key: '0-1',
value: '实例'
}
]
},
数据一进来,只有rulename,需要一个专门根据type来渲染组件的渲染变量
let renderComponent;
switch(type){
case "rulename":
renderComponent = (<div>123</div>)
break;
default:
renderComponent=null
break;
}
遇到的问题 一开始写的递归
if(!!dataSource.children){
dataSource.children.map(item=>{
let {children,{...rest}}=item
return <TreeNode dataSource={children} {...rest}/>
})
}
这样写会有一个问题 结合起来看
let { dataSource } =this.props
let {type,key,value}={...dataSource}; //children递归回来,已经没有type,key,value了
let renderRoot;
let renderTreeNode = [];
if(!!dataSource.children){
renderTreeNode=dataSource.children.map(item=>{
let {children,{...rest}}=item
//{...rest} 里面包含的是我这一层需要的type,key,value
return <TreeNode dataSource={children} {...rest}/>
//问题所在,children递归回去,没有我要的东西了
})
}
switch(type){
case "rulename":
renderRoot = (<div>123</div>)
break;
default:
renderRoot=null
break;
}
急需解决的问题:
1.children递归回来,没有type,key,value了,全部留在递归前的{...rest}了,怎么根据取出来去渲染呢?
2.renderRoot和renderTreeNode不能同时被渲染出来,rulename和ruleConditions,action没法共同渲染
3.而且children里面还有其他字段需要传递给组件,无法传出去给组件,继续完成递归
解决思路:
1.我把type和children单独拿出来,其他参数我不管,传进传出,自己去传,自己去解构
2.渲染需要两个变量来自动完成,一个变量渲染父节点,一个变量渲染子节点
3.其余的数据结构里面的字段,全部传过去,自己去解构
我需要
1.一个专门负责递归的函数,并能渲染子组件的变量
(递归children的函数和渲染children的变量)
let { dataSource } =this.props
let {type,children,...rest}={...dataSource}; //把type和children单独拿出来
if(children){
renderTreeNode=this.reduceChild(children,renderTreeNode)
}
/**
* @func reduceChild
* @desc 如果有children,进行TreeNode递归,
* @param ChildData 传过来的children数据
* @param renderTreeNode 专门用来渲染子节点的数组,reduceChild要返回回去一个新的渲染数组
*/
reduceChild(ChildData,renderTreeNode){
return renderTreeNode=ChildData.map((item,index)=>{
return <TreeNode dataSource={item} key={index}/>
})
}
遍历的时候需要个唯一的key,通过加index解决
遍历时报的错
2.一个专门负责根据type渲染组件的函数
let renderRoot;
renderRoot=this.JudgeType(type,{...rest}) //TreeData里的rulename
/**
* @func JudgeType
* @desc 根据数据结构里的type字段渲染不同的组件
* @param type 数据结构里面的type字段
* @param rest 数据结构里面除了type外的其他字段内容,需要哪个字段,就解构出来
*/
JudgeType(type,rest){
let renderComponent;
let {value,key}={...rest}
switch(type){
case "rulename":
renderComponent = (<InputInTree value={value} uid={key} onChange={this.onInputChange.bind(this)}/>)
break;
case "ruleConditions":
renderComponent =(<Add value={value} isAddShow={true} uid={key} addItem={this.addCondition.bind(this)} key="0-0"/>)
break;
case "editCondition":
renderComponent =(<TwoInputAndSelectInTree isDeleteShow={true} uid={key} deleteItem={this.deleteItemCondition.bind(this)}/>)
break;
case "action":
renderComponent =(<Add value={value} isAddShow={true} uid={key} addItem={this.addCondition.bind(this)} key="0-1"/>)
break;
case "actionInstance":
renderComponent =(<SelectInTree isAddShow={true} isDeleteShow={true}/>)
break;
case "config":
renderComponent =(<SelectInTree isAddShow={true} isDeleteShow={true}/>)
break;
case "Type":
renderComponent =(<SelectInTree isDeleteShow={true}/>)
break;
default:
renderComponent=null
break;
}
return renderComponent;
}
完整代码段
import React from 'react';
import './TreeNode.scss'
import '../EditComponent/index.scss'
import { Icon} from "@alife/next";
import InputInTree from "../EditComponent/InputInTree/InputInTree"
import Add from '../EditComponent/Add/Add'
import TwoInputAndSelectInTree from '../EditComponent/TwoInputAndSelectInTree/TwoInputAndSelectInTree'
import SelectInTree from "../EditComponent/SelectInTree/SelectInTree"
const deepClone=obj=>{
return JSON.parse(JSON.stringify(obj))
}
class TreeNode extends React.Component {
addCondition(addConditionkey){
console.log(addConditionkey)
}
deleteItemCondition(deleteConditionKey){
console.log(deleteConditionKey)
}
onInputChange(key,value){
console.log(key,value)
}
/**
* @func JudgeType
* @desc 根据数据结构里的type字段渲染不同的组件
* @param type 数据结构里面的type字段
* @param rest 数据结构里面除了type外的其他字段内容,需要哪个字段,就解构出来
*/
JudgeType(type,rest){
let renderComponent;
let {value,key}={...rest}
switch(type){
case "rulename":
renderComponent = (<InputInTree value={value} uid={key} onChange={this.onInputChange.bind(this)}/>)
break;
case "ruleConditions":
renderComponent =(<Add value={value} isAddShow={true} uid={key} addItem={this.addCondition.bind(this)} key="0-0"/>)
break;
case "editCondition":
renderComponent =(<TwoInputAndSelectInTree isDeleteShow={true} uid={key} deleteItem={this.deleteItemCondition.bind(this)}/>)
break;
case "action":
renderComponent =(<Add value={value} isAddShow={true} uid={key} addItem={this.addCondition.bind(this)} key="0-1"/>)
break;
case "actionInstance":
renderComponent =(<SelectInTree isAddShow={true} isDeleteShow={true}/>)
break;
case "config":
renderComponent =(<SelectInTree isAddShow={true} isDeleteShow={true}/>)
break;
case "Type":
renderComponent =(<SelectInTree isDeleteShow={true}/>)
break;
default:
renderComponent=null
break;
}
return renderComponent;
}
/**
* @func reduceChild
* @desc 如果有children,进行TreeNode递归,
* @param ChildData 传过来的children数据
* @param renderTreeNode 专门用来渲染子节点的数组,reduceChild要返回回去一个新的渲染数组
*/
reduceChild(ChildData,renderTreeNode){
return renderTreeNode=ChildData.map((item,index)=>{
return <TreeNode dataSource={item} key={index}/>
})
}
/**
* @func reduceChild
* @desc TreeData一进来是一个对象,
type要用来判断显示怎么样的组件,
children要用来递归
{...rest}里面包含了除了type和children的其他字段传给组件,
比如:需要的value和key,传给自定义组件去使用
* @param renderRoot //专门负责渲染最上层的rulename
* @param renderTreeNode //专门负责渲染子节点的数组
*/
render() {
let { dataSource } =this.props
let {type,children,...rest}={...dataSource}; //把type和children单独拿出来
let renderRoot;
let renderTreeNode = [];
if(children){
renderTreeNode=this.reduceChild(children,renderTreeNode)
}
renderRoot=this.JudgeType(type,{...rest})//TreeData里的rulename
return (
<div className="treenode">
<div className="title">
<Icon type="arrow-down" size='xs' />
<span>
{renderRoot}
</span>
</div>
<div className="context">
{renderTreeNode}
</div>
</div>
)
}
}
export default TreeNode;
网友评论