1. 程式人生 > 其它 >重構-樹形結構(左側多級選單)

重構-樹形結構(左側多級選單)

技術標籤:手寫重構UI框架javascript

實現多級展示:
	遞迴元件

實現點選顯示/隱藏子選單:
	利用js物件特性,無屬性也可以新增,即每個屬性添加個flag,用來控制是否顯示當前標籤的子標籤
	即點選當前標籤,給渲染資料的物件新增flag,決定子標籤是否顯示

傳遞引數結構:
[{label:'標籤名',children:[{label:'子標名'}]}]

缺陷:
	高度未知,使用max-height做過渡,會有延遲

效果圖:
在這裡插入圖片描述
在這裡插入圖片描述
程式碼示例:
使用:

import React,{useState} from 'react'
import Tree from './tree/tree'
const data=[{ label: '一級 1', children: [{ label: '二級 1-1', children: [{ label: '三級 1-1-1' }] }] }, { label: '一級 2', children: [{ label: '二級 2-1', children: [{ label: '三級 2-1-1' }] }, { label: '二級 2-2', children: [{ label: '三級 2-2-1'
}] }] }, { label: '一級 3', children: [{ label: '二級 3-1', children: [{ label: '三級 3-1-1' }] }, { label: '二級 3-2', children: [{ label: '三級 3-2-1' }] }] } ] function App(){ return( <div> <Tree data={data}></Tree> <
/div> ) } export default App

tree容器.jsx:

import React, { useState,useCallback,useMemo,useRef,useEffect } from 'react'
import PropTypes from 'prop-types';
import TreeItem from './treeItem/treeItem'
import './tree.css'

function App(props){

  let [data, setData] = useState([]);

  useEffect(() => {
    setData(props.data)
    
  },[props.data])
  

  return(

    <div className='jf-tree-container'>
      <div>
        <TreeItem data={data} itemHeight={props.itemHeight}></TreeItem>
      </div>
    </div>
  )
}

App.propTypes = {
  data: PropTypes.array,
  itemHeight:PropTypes.string
}

App.defaultProps = {
  data: [],
  depIndex: 0,
  itemHeight:'40px'
}

// memo
export default App;

tree容器.css:

.jf-tree-container {
  display: inline-block;
  box-sizing: border-box;
  background-color: var(--backgroundColor);
  width: var(--width);
  height: var(--height);
  overflow-x: hidden;
  overflow-y: auto;

  --width: 200px;
  --height: 400px;
  --backgroundColor: #409eff;
  --hoverColor: #eee;
}

treeItem.jsx:

import React, { useState,useCallback,useMemo,useRef,useEffect } from 'react'
import PropTypes from 'prop-types';
import './treeItem.css'

function App(props){

  let [data, setData] = useState([]);
  const treeItemf = useRef(null);
  const [height, setHeight] = useState(0);
    
  useEffect(() => {
    setData(props.data)

    
  },[props.data])
  

  const _onClick = function (index,e)
  {
    //利用js物件特性,無屬性也可以新增,即加上每個屬性都有個flag,用來控制是否顯示當前標籤的子標籤
    if (data[index].children)
    {
      data[index].flag = !data[index].flag;
      setData([...data]);
    }
  }

  return(

    <div >
      <div>

        {
          data.map((item, indexOne) => {
            
            return (
              <div key={item + indexOne} className='jf-tree-item'>
                {<span style={{ paddingLeft: props.depIndex * 10 + 'px' }} onClick={(e) => _onClick(indexOne, e)} className={`jf-tree-label`}>{item.label}</span>}
                <div className={`jf-tree-item-children ${item.flag&&'show'}` }>
                  {
                    
                    item.children && <App itemHeight={props.itemHeight} data={item.children} depIndex={props.depIndex + 1}></App>
                    
                    
                  }
                 </div>
              </div>
            )
          })
        }
      </div>
    </div>
  )
}

App.propTypes = {
  data: PropTypes.array,
  
}

App.defaultProps = {
  data: [],
  depIndex:0
}

// memo
export default React.memo(App);

treeItem.css:

.jf-tree-item {
  /* display: inline-block; */
  box-sizing: border-box;
  overflow: hidden;

  --hoverColor: #eee;
  --childrenColor: skyblue;
  --childrenHeight: 0;
}

.jf-tree-label {
  cursor: pointer;
  display: inline-block;
  width: 100%;
  height: 40px;
  color: white;
  line-height: 40px;
  overflow: hidden;
}

.jf-tree-item-children {
  background-color: var(--childrenColor);
  max-height: 0;
  transition: max-height 0.5s;
}

.show {
  max-height: 400px;
}

.jf-tree-label:hover {
  background-color: var(--hoverColor);
}