重構-樹形結構(左側多級選單)
阿新 • • 發佈:2020-12-11
技術標籤:手寫重構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);
}