【封装Tree的思路】

封装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;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容