React實踐之Tree組件

React實踐之Tree組件

實現功能 node

  • 渲染數據
  • 展開合併

使用 react

  • 數據結構:
const node = {
  title: '00000',  
  key: '0' ,
  level:'level1',
  open: true,
  child:[  
      {
        title: '0-111111', 
        key: '0-0',
        level:'level2',
        open: true,
        child:[  
            {  
              title: '0-1-1111', 
              key: '0-0-0',
              level:'level3',    
            }, 
            {  
              title: '0-1-2222', 
              key: '0-0-1',
              level:'level3',
              open: true,
              child: [
                  {  
                  title: '0-1-2-11111', 
                  key: '0-0-1-0',
                  level:'level4',
                  open: true,
                  child: [
                      {  
                      title: '0-1-2-1-111', 
                      key: '0-0-1-0-0',
                      level:'level5',
                    }
                  ]
                }
              ]
            },
            {  
              title: '0-1-33333', 
              key: '0-0-4',
              level:'level3',
            }, 
        ]
      },
      {
        title: '0-222222', 
        key: '0-2',
        level:'level2',
        open: false,
        child: [
          {
            title: '0-2-1111', 
            key: '0-2-0',
            level:'level3',
          },
          {
            title: '0-2-22222', 
            key: '0-2-1',
            level:'level3',
          },
          {
            title: '0-2-33333', 
            key: '0-2-2',
            level:'level3',
          }
        ]
      }
  ]
}
  • 引用代碼:
<div>
    <Tree 
        treeList = {node}
    /> 
</div>
  • 組件實現代碼:
import React, { Component } from 'react';
import classNames from 'classnames';
const history = createHistory();
import {
    BrowserRouter as Router,
    HashRouter,
    Route,
    Link,
    Switch,
    NavLink
  } from 'react-router-dom';

class Tree extends Component {

    constructor(props){
        super(props)
        this.treeItemCroup    = this.treeItemCroup.bind(this);
        this.handleClick      = this.handleClick.bind(this);

        this.state ={
            openList : false
        }
    }

    handleClick(e) {
        // 這是點擊➡️ 時調用的方法
        // 若是當前這個➡️ 沒有旋轉,那就設置旋轉,視覺效果
        e.target.style.transform = e.target.style.transform == "rotate(-90deg)" ? "rotate(0deg)" : "rotate(-90deg)"
        for(let item in e.target.parentNode.parentNode.childNodes){
            // 點擊的時候設置當前層級的子元素素隱藏
            // 操做了DOM,我很難受
            if(item > 0){
                e.target.parentNode.parentNode.childNodes[item].style.display = e.target.parentNode.parentNode.childNodes[item].style.display === 'none' ? 'block' : 'none' 
            }
        }
    }
    
    itemTitle(item){
        // 這個是返回title,由於有時候是點擊一個連接,因此設置了兩種狀況,若是node節點裏面有component這個節點,那就設置成能夠點擊跳轉
        if(item.component){ 
            return (<Link to={ item.component } >
                         <span onClick={this.handleClick.bind(this)}>{item.title}</span>
                    </Link>)
        }else{
            return (
                 <span onClick={this.handleClick.bind(this)}>{item.title}</span>
            )
        }
    }

    treeItemCroup(itemGroup) {
        let itemGroupItem = []
        // 每一個元素的樣式,根據當前等級來設置樣式,level1的就縮緊20px,level2的縮緊40px,一次類推,在視覺上呈現樹的形式
        let itemStyle = {
                paddingLeft: 20*parseInt(itemGroup.level.slice(5), 10)+'px'
            }
        // 若是當前節點還有子元素,就設置一個➡️ 箭頭 ,能夠點擊展開。
        let iconChevron = classNames('fa',{'fa-chevron-down' : itemGroup.child})
        // 把全部節點放在一個數組裏面
        itemGroupItem.push(
            <ul>
                {/* 第一個層級 */}
                <li className={itemGroup.level} key={itemGroup.key} style={itemStyle}>
                    <i aria-hidden="true" className={iconChevron} onClick={this.handleClick.bind(this)}></i>
                    {this.itemTitle(itemGroup)}
                </li>
                {/* 調用tree方法 */}
                {this.tree(itemGroup.child)}
            </ul>
        )
        return itemGroupItem
    }

    tree(child){
        let treeItem
        // 若是有子元素
        if(child){  
            // 子元素是數組的形式,把全部的子元素循環出來
            treeItem = child.map((item, key) => {
                // 同理,設置樣式
                let itemStyle = {
                    paddingLeft: 20*parseInt(item.level.slice(5), 10)+'px'
                }
                // 同理,設置➡️ 
                let iconChevron = classNames('fa',{'fa-chevron-down' : item.child})
                return  (
                    <ul>
                        <li className={item.level} key={key} style={itemStyle}>
                           <i aria-hidden="true" className={iconChevron} onClick={this.handleClick.bind(this)}></i>
                            {this.itemTitle(item)}
                        </li>
                        {/* 若是當前子元素還有子元素,就遞歸使用tree方法,把當前子元素的子元素渲染出來 */}
                        {this.tree(item.child)}
                    </ul>
                )
            })
        }
        return treeItem
    }

    render() {
        return (
            <div className="tree">
                { this.treeItemCroup(this.props.treeList) }
            </div>
        );
    }
}

export default Tree;
  • 效果圖:
    圖片描述
  • DOM結構圖
    圖片描述

圖片描述
代碼我加了一些註釋,可能仍是比較難理清楚邏輯 ?
當前的邏輯我以爲有點混亂,但願看的朋友們能給出一點建議,感激涕零數組

相關文章
相關標籤/搜索