美文网首页程序员
【封装Tree的思路】

【封装Tree的思路】

作者: Romyo | 来源:发表于2018-05-03 12:16 被阅读0次

    封装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;
    

    相关文章

      网友评论

        本文标题:【封装Tree的思路】

        本文链接:https://www.haomeiwen.com/subject/fyukrftx.html