antd-tree树形组件带搜索框的实际应用
目录
antd-tree树形组件带搜索框的实际应用
需求视图
import React, { Component } from 'react'; import { Form, Input, Tree } from 'antd'; const TreeNode=Tree.TreeNode; const { Search } = Input; const treeData = [ { deptName: '总部', deptId: 'HQ001', children: [ { proName: '金街大厦', proId: 'ea23sdf', children: [ { proName: 'ceshi', proId: '15478cc' }, { proName: '测试项目', proId: 'cvb25sa' }, { proName: 'xxceshiyi', proId: 'f95esc2' }, ], }, { proName: '金街管理', proId: 'f23564d', children: [ { proName: '测试新增项目', proId: '25dfbn3' }, { proName: '建筑', proId: 'rt89gh2' }, { proName: '0-0-1-2', proId: 'sd9562v' }, ], }, { proName: 'haha', proId: '23148dg', }, ], }, { deptName: '北京', deptId: '548cvfg', children: [ { proName: '北京1', proId: '1236llo' }, { proName: '叨叨', proId: 'ea82ssk' }, { proName: 'beijing', proId: 'fyu831x' }, ], }, { deptName: '上海', deptId: '54fae89', }, ]; class Index extends Component { constructor(props) { super(props); this.state = { loading: false, expandedKeys: [], // 存树节点展开key treeData: [] autoExpandParent: false, // 默认层级不展开 } } expandedKeysFun = (treeData) => { // 展开 key函数 if (treeData && treeData.length == 0) { return []; } //console.log(treeData) let arr = []; const expandedFn = (Data) => { Data.map((item, index) => { arr.push(item.key); if (item.children && item.children.length > 0) { expandedKeysFn(item.children); } }) } // 执行expandedFn函数,把treeData传给Data expandedFn(treeData); return arr; } // 点击搜索:若有子级符合搜索条件,显示展开过滤搜索出的子级;不符合的就不显示出来 onSearch = (value) => { // 搜索框 if (value == "") { // 为空时层级不展开 // 还要调接口刷新下页面,接口我略写 axios.post('', {}).then(res => {}) this.setState({ expandedKeys: [], autoExpandParent: false, // 不展开层级 loading: false, }) } else { let res = this.arrayTreeFilter(treeData, this.filterFn, value); let expkey = this.expandedKeysFun(res); this.setState({ expandedKeys: expkey, autoExpandParent: true, }) } } // 过滤数据 arrayTreeFilter = (data, predicate, filterText) => { const nodes = data; // 如果已经没有节点了,结束递归 if (!(nodes && nodes.length)) { return; } const newChildren = []; for (const node of nodes) { // for..of循环, node即item if (predicate(node, filterText)) { // 如果自己(节点)符合条件,直接加入到新的节点集 newChildren.push(node); // 并接着处理其 children,(因为父节点符合,子节点一定要在,所以这一步就不递归了) if(node.children && node.children.length > 0) { node.children = this.arrayTreeFilter(node.children, predicate, filterText); } } else { // 如果自己不符合条件,需要根据子集来判断它是否将其加入新节点集 // 根据递归调用 arrayTreeFilter() 的返回值来判断 const subs = this.arrayTreeFilter(node.children, predicate, filterText); // 以下两个条件任何一个成立,当前节点都应该加入到新子节点集中 // 1. 子孙节点中存在符合条件的,即 subs 数组中有值 // 2. 自己本身符合条件 if ((subs && subs.length) || predicate(node, filterText)) { node.children = subs; newChildren.push(node); } } } return newChildren; } //过滤函数 filterFn = (data, filterText) => { if (!filterText) { return true; } return ( new RegExp(filterText, "i").test(data.deptName|| data.proName) //根据xxname过滤 ,因为父级name与子级name不一样,写个|| ); } // 1. 生成树结构函数 // 项目列表渲染的方法 renderTreeNode = (data) => { if (data.length == 0) { return } let { expandedKeys, searchValue } = this.state; return data && data.length > 0 && data.map((item) => { if (item.children && item.children.length > 0) { return ( <TreeNode value={item.deptName} key={item.deptId} title={item.deptName} dataRef={item}> {/* 展示父级数据 */} {this.renderTreeNode(item.children)} </TreeNode> ) } // 展示子级的数据 return <TreeNode value={item.proName} key={item.proId} title={item.proName} dataRef={item}></TreeNode> }) } onExpand = expandedKeys => { this.setState({ expandedKeys, autoExpandParent: false, }); }; render() { const { expandedKeys, treeData, autoExpandParent, loading } = this.state; return ( <div> <div>项目列表</div> <Search placeholder="请输入项目名称" enterButton="检索" onSearch={value => this.onSearch(value)} /> <div className={styles.listParentStyle}> <Spin loading={loading}> <Tree allowClear onExpand={this.onExpand} expandedKeys={expandedKeys} autoExpandParent={autoExpandParent} blockNode // 节点占据一行,这样点击话不用必须点击字本身上才触发 > {this.renderTreeNode(treeData)} </Tree> </Spin> </div> </div> ) } } export default Index
**拓展—-
如果标题太长想要省略,还想要有文字提示Tooltip或者气泡卡片Popover**
部分代码:
import cutStringLength from 'utils/utils' .... return data && data.length > 0 && data.map((item) => { if (item.children && item.children.length > 0) { return ( <TreeNode value={item.deptName} key={item.deptId} title={<Popover content={item.deptName} trigger='hover' palcement='right'><span style={{ border:'1px solid #fff', display: 'block'}}>{cutStringLength(item.deptName, 20)}</span></Popover>} dataRef={item} className={styles.listStyle}> {/* 展示父级数据 */} {this.renderTreeNode(item.children)} </TreeNode> ) } // 展示子级的数据 return <TreeNode value={item.proName} key={item.proId} title={<Popover content={item.proName} trigger='hover' palcement='right'><span style={{ border:'1px solid #fff', display: 'block'}}>{cutStringLength(item.proName, 20)}</span></Popover>} dataRef={item}></TreeNode> }) styles文件 .listParentStyle { ul li { span:nth-child(2n){ font-weight:600; } } .listStyle { ul li { span:nth-child(2n){ font-weight:400; } } ul li .ant-tree-node-content-wrapper:hover { background-color: #f0fbff; } } } utils/utils文件: // strName 文本 len长度 export function cutStringLength (strName, len) { if(strName == null) { return '' } if(strName.length > len) { return `${strName.substring(0, len-1)}...` } return strName }
参考图片
即使不用点击文字本身,点击文字所在当前行,这行文字也会被点中,并且显示背景色
项目中用到Tree组件,并且还能进行搜索
代码供参考
博主写的不错:
相关文章