前言:
最近再用Tree组件做项目,记录一下使用方法。
一、预期的效果
antd-tree带搜索框的示例(官网):官网只是标红
我预期的效果是搜索并且标红(官网示例)。下面是我参考官网的示例写出来的。
二、antd-tree组件带搜索框的使用及踩坑(只标红)
import React, { Component } from 'react';
import { Tree, Input } from 'antd';
import styles from '../../assets/index.css';
const { TreeNode } = Tree;
const { Search } = Input;
class Index extends Component {
constructor(props) {
super(props)
this.state = {
data: [
{
title: "十三中学",
key: 1,
children: [
{
title: "初一年级",
key: 2,
children: [
{
title: "一班",
key: 3,
},
{
title: "二班",
key: 4,
}
]
},
{
title: "初二年级",
key: 20,
}
]
},
{
title: "八十中学",
key: 5,
children: [
{
title: "初一年级",
key: 6,
children: [
{
title: "一班",
key: 7,
children: [
]
},
{
title: "二班",
key: 8,
children: [
{
title: "一组",
key: 9,
children: []
},
{
title: "vv组",
key: 999,
children: []
}
]
}
]
},
{
title: "初二年级",
key: 55,
children: []
}
]
}
],
expandedKeys: [], //展开的key值
autoExpandParent: true,
checkedKeys: [], //选中的key,
searchValue: '',
searchTreeKey: [] //搜索得key
}
}
//给子级添加父级Key
addParentKeyWrapper = (tree) => {
//深度克隆
const data = JSON.parse(JSON.stringify(tree));
function addParentKey(data, parentKey) {
data.forEach(ele => {
const { children, key } = ele;
ele.parent_key = parentKey;
if (children) {//如果唯一标识不是code可以自行改变
addParentKey(children, key)
}
})
}
addParentKey(data, null); //一开始为null,根节点没有父级
return data;
}
componentDidMount() {
this.expandedKeysFn();
this.setState({
data: this.addParentKeyWrapper(this.state.data) //调用添加父元素key
})
}
onChange = (e) => { //search变化
const { value } = e.target;
console.log(value)
const dataList = [];
if (value) {
const generateList = data => { //tree树片扁平化
for (let i = 0; i < data.length; i++) {
const node = data[i];
const { key, title, parent_key } = node;
dataList.push({ key, title: title, parent_key: parent_key }); //根据自己的数据更换parent_key代表父级key
if (node.children) {
generateList(node.children);
}
}
};
generateList(this.state.data);
const getParentKey = (key, tree) => { //获取父元素可以
let parentKey;
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.children) {
if (node.children.some(item => item.key === key)) {
parentKey = node.key;
} else if (getParentKey(key, node.children)) {
parentKey = getParentKey(key, node.children);
}
}
}
return parentKey;
};
const expandedKeys = dataList
.map(item => {
if (item.title.indexOf(value) > -1) {
return getParentKey(item.key, this.state.data);
}
return null;
})
.filter((item, i, self) => item && self.indexOf(item) === i);
this.setState({
expandedKeys: expandedKeys,
searchValue: value,
autoExpandParent: true
})
} else {
this.expandedKeysFn() //重置展开key
this.setState({
searchValue: value,
autoExpandParent: true
})
}
}
renderTreeNode = (data) => { //生成树结构函数
if (data.length == 0) {
return
}
let {searchValue}=this.state;
return data.map((item) => {
const index = item.title.indexOf(searchValue);
const beforeStr = item.title.substr(0, index);
const afterStr = item.title.substr(index + searchValue.length);
const title =
index > -1 ? (
<span>
{beforeStr}
<span style={{ color: "red" }}>{searchValue}</span>
{afterStr}
</span>
) : (
<span>{item.title}</span>
);
if (item.children && item.children.length > 0) {
//className={searchTreeKey.indexOf(item.key) > -1 ? styles.yes : styles.no}
return <TreeNode title={title} key={item.key} >
{
this.renderTreeNode(item.children)
}
</TreeNode>
}
return <TreeNode key={item.key} title={title} ></TreeNode>
})
}
expandedKeysFn = () => {
let { data } = this.state;
let arr = [];
let loop = (data) => {
data.map((item, index) => {
arr.push(item.key);
if (item.children && item.children.length > 0) {
loop(item.children)
}
})
}
loop(data);
this.setState({
expandedKeys: arr
})
}
onExpand = expandedKeys => {
console.log('onExpand', expandedKeys);
this.setState({
expandedKeys,
autoExpandParent: false
});
};
onCheck = (checkedKeys) => {
this.setState({ checkedKeys })
}
render() {
let { data, expandedKeys, autoExpandParent, checkedKeys } = this.state;
return (
<div>
<Search style={{ marginBottom: 8 }} placeholder="Search" onChange={this.onChange} />
<Tree
checkable
expandedKeys={expandedKeys} //默认展开的key
onExpand={this.onExpand} //展开事件
autoExpandParent={autoExpandParent} //是否自动展开父节点
checkedKeys={checkedKeys} //选中的key
onCheck={this.onCheck} //选中事件
>
{this.renderTreeNode(data)}
</Tree>
</div>
);
}
}
export default Index
index.css
.yes{
display: block;
}
.no{
display: none;
}
hook语法
import React, { Component, useEffect, useState } from 'react';
import { Tree, Input } from 'antd';
import styles from '../../assets/index.css';
const { TreeNode } = Tree;
const { Search } = Input;
function Index(props) {
let arr = [
{
title: "十三中学",
key: 1,
children: [
{
title: "初一年级",
key: 2,
children: [
{
title: "一班",
key: 3,
},
{
title: "二班",
key: 4,
}
]
},
{
title: "初二年级",
key: 20,
}
]
},
{
title: "八十中学",
key: 5,
children: [
{
title: "初一年级",
key: 6,
children: [
{
title: "一班",
key: 7,
children: [
]
},
{
title: "二班",
key: 8,
children: [
{
title: "一组",
key: 9,
children: []
},
{
title: "vv组",
key: 999,
children: []
}
]
}
]
},
{
title: "初二年级",
key: 55,
children: []
}
]
}
]
const [data, setData] = useState(arr); // 树形 数据
const [expandedKeys, setExpandedKeys] = useState([]); // 展开的key值
const [autoExpandParent, setAutoExpandParent] = useState(true); // 是否自动展开父节点
const [checkedKeys, setCheckedKeys] = useState([]); // 选中的key
const [searchValue, setSearchValue] = useState(""); // 搜索的值
const [searchTreeKey, setSearchTreeKey] = useState([]); // 搜索得key
useEffect(()=>{
expandedKeysFn();
setData(addParentKeyWrapper(data));
},[])
const addParentKeyWrapper = (tree) => {
//深度克隆
const data = JSON.parse(JSON.stringify(tree));
function addParentKey(data, parentKey) {
data.forEach(ele => {
const { children, key } = ele;
ele.parent_key = parentKey;
if (children) {//如果唯一标识不是code可以自行改变
addParentKey(children, key)
}
})
}
addParentKey(data, null); //一开始为null,根节点没有父级
return data;
}
const onChange = (e) => { //search变化
const { value } = e.target;
console.log(value)
const dataList = [];
if (value) {
const generateList = data => { //tree树片扁平化
for (let i = 0; i < data.length; i++) {
const node = data[i];
const { key, title, parent_key } = node;
dataList.push({ key, title: title, parent_key: parent_key }); //根据自己的数据更换parent_key代表父级key
if (node.children) {
generateList(node.children);
}
}
};
generateList(data);
const getParentKey = (key, tree) => { //获取父元素可以
let parentKey;
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.children) {
if (node.children.some(item => item.key === key)) {
parentKey = node.key;
} else if (getParentKey(key, node.children)) {
parentKey = getParentKey(key, node.children);
}
}
}
return parentKey;
};
const expandedKeys = dataList
.map(item => {
if (item.title.indexOf(value) > -1) {
return getParentKey(item.key, data);
}
return null;
})
.filter((item, i, self) => item && self.indexOf(item) === i);
setExpandedKeys(expandedKeys);
setSearchValue(value);
setAutoExpandParent(true);
} else {
expandedKeysFn() //重置展开key
setSearchValue(value);
setAutoExpandParent(true);
}
}
const renderTreeNode = (data) => { //生成树结构函数
if (data.length == 0) {
return
}
return data.map((item) => {
const index = item.title.indexOf(searchValue);
const beforeStr = item.title.substr(0, index);
const afterStr = item.title.substr(index + searchValue.length);
const title =
index > -1 ? (
<span>
{beforeStr}
<span style={{ color: "red" }}>{searchValue}</span>
{afterStr}
</span>
) : (
<span>{item.title}</span>
);
if (item.children && item.children.length > 0) {
//className={searchTreeKey.indexOf(item.key) > -1 ? styles.yes : styles.no}
return <TreeNode title={title} key={item.key} >
{
renderTreeNode(item.children)
}
</TreeNode>
}
return <TreeNode key={item.key} title={title} ></TreeNode>
})
}
const expandedKeysFn = () => {
let arr = [];
let loop = (data) => {
data.map((item, index) => {
arr.push(item.key);
if (item.children && item.children.length > 0) {
loop(item.children)
}
})
}
loop(data);
setExpandedKeys(arr);
}
const onExpand = expandedKeys => {
console.log('onExpand', expandedKeys);
setExpandedKeys(expandedKeys);
setAutoExpandParent(false);
};
const onCheck = (checkedKeys) => {
setCheckedKeys(checkedKeys);
}
return (
<div>
<Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onChange} />
<Tree
checkable
expandedKeys={expandedKeys} //默认展开的key
onExpand={onExpand} //展开事件
autoExpandParent={autoExpandParent} //是否自动展开父节点
checkedKeys={checkedKeys} //选中的key
onCheck={onCheck} //选中事件
>
{renderTreeNode(data)}
</Tree>
</div>
)
}
export default Index
数据量大造成的卡顿
可以给Tree加一个height属性:使用 height
属性则切换为虚拟滚动。
<Tree height={500}/>
这样可以缓解卡顿现象
antd tree虚拟滚动