antd 的 Tree 控件没有提供点击展开的功能,只能通过左边的三角形实现展开和收起,没办法只好自己实现这个功能。

先看效果



如图实现的是类似 Mac 文件目录形式的结构,有箭头代表是个文件夹,点击展开文件夹,点击外层文件夹可以收起整个文件夹。

首先根据服务器返回的 Json 数据生成树形结构

const data = {
name: "root",
children: [{
name: "a",
value: "/a",
children: [{
name: "file_1",
value: "/a/file_1"
}, {
name: "a_1",
value: "/a/a_1",
children: [{
name: "file_2",
value: "/a/a_1/file_2"
}, {
name: "file_3",
value: "/a/a_1/file_3"
}]
}, {
name: "a_2",
value: "/a/a_2",
children: [{
name: "file_4",
value: "/a/a_2/file_4"
}, {
name: "file_5",
value: "/a/a_2/file_5"
}]
}]
}, {
name: "b",
value: "/b",
children: [{
name: "b_1",
value: "/b/b_1",
children: [{
name: "file_6",
value: "/b/b_1/file_6"
}]
}]
}]
}

数据结构中有 children 字段代表是个文件夹,因此需要递归遍历出 TreeNode 视图

import React from "react";
import Tree from 'antd/lib/tree';
import 'antd/lib/tree/style/css'; const TreeNode = Tree.TreeNode; class TreeView extends React.Component {
//遍历json绘制出tree结构
mapData = (children) => {
if (children && Array.isArray(children)) {
return children.map((ele) => {
if (ele.children && Array.isArray(ele.children)) {
return <TreeNode title={ele.name} key={ele.value}>
{this.mapData(ele.children)}
</TreeNode>
} else {
return <TreeNode title={ele.name} key={ele.value}/>
}
})
}
return []
} render() {
let content = [] let {name, children} = data
if (name) {
content.push(<TreeNode title={name} key="/">{this.mapData(children)}</TreeNode>)
} return (
<Tree>
{content}
</Tree>
);
}
} export default TreeView

已经完成第一步,生成树形结构视图。接下来就是要实现点击展开树形结构

state = {
expandedKeys: ["/"],
autoExpandParent: true,
selectedKeys: []
} //选中的回调
onSelect = (selectedKeys, obj) => {
let {expandedKeys} = this.state
let selectedKey = this.state.selectedKeys
//选中的状态
if (obj.selected) {
//判断是否已经展开,未展开就添加到 expandedKeys 中
//已经展开就不用管
let index = expandedKeys.indexOf(selectedKeys[0])
if (index === -1) {
expandedKeys.push(selectedKeys[0])
this.setState({
expandedKeys: expandedKeys,
selectedKeys: selectedKeys
})
} else {
this.setState({
selectedKeys: selectedKeys
})
} // 没有 children 代表当前已没有下一级目录
if (obj.event && obj.selectedNodes.length === 1 && !obj.selectedNodes[0].props.children) {
//do something
}
} else {
//selectedKey 是上次选中的元素 在 expandedKeys 肯定是存在的
//找到下标后需要过滤掉子类目录 例如上次选中的元素为 /a ,
//子类 /a/a_1 已经展开就需要从 expandedKeys 中移除这个元素
let index = expandedKeys.indexOf(selectedKey[0])
if (index !== -1) {
//过渡掉子类元素
expandedKeys = expandedKeys.filter((ele) => {
return !ele.includes(selectedKey[0])
})
this.setState({
expandedKeys: expandedKeys,
selectedKeys: []
})
} else {
this.setState({
selectedKeys: []
})
}
}
} //展开的回调
onExpend = (expandedKey, obj) => {
let {expandedKeys} = this.state
//展开的状态
if (obj.expanded) {
this.setState({
expandedKeys: expandedKey,
selectedKeys: []
})
} else {
//expandedKey 返回的是当前已经展开的元素 expandedKeys 是上次展开的元素
//比较两个数组中缺少的元素得出当前被收起的是哪个元素
let removeArray = this.diffArray(expandedKey, expandedKeys)
//收起的时候需要把里面展开的元素一并移除,不然会造成收起动作无效
expandedKeys = expandedKeys.filter((ele) => {
return !ele.includes(removeArray[0])
})
this.setState({
expandedKeys: expandedKeys,
selectedKeys: []
})
}
} //比较出2个数组中不一样的元素
diffArray = (arr1, arr2) => {
let arr3 = [];
for (let i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) === -1)
arr3.push(arr1[i]);
}
for (let j = 0; j < arr2.length; j++) {
if (arr1.indexOf(arr2[j]) === -1)
arr3.push(arr2[j]);
}
return arr3;
}
......
render() {
return (
<Tree
onExpand={this.onExpend}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onSelect={this.onSelect}
selectedKeys={this.state.selectedKeys}>
{content}
</Tree>
)
}

根index.js文件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker'; ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

根APP组件

import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import TreeView from "./TreeView"; class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo"/>
</div>
<div style={{marginTop: "100px"}}>
<TreeView/>
</div>
</div>
);
}
} export default App;

本文学习自:https://www.jianshu.com/p/d104f491b8c9

antd的Tree控件实现点击展开功能的更多相关文章

  1. vue+element项目中使用el-dialog弹出Tree控件报错问题

    1. 按正常的点击按钮,显示dialog弹出的Tree控件,然后把该条数据下的已经选中的checkbox , 用setCheckedNodes或者setCheckedKeys方法选择上 , 报下面这个 ...

  2. ElementUI Tree控件在懒加载模式下的重新加载和模糊查询

    之所以使用懒加载是为了提高性能,而且只有在懒加载模式下默认会给所有显示节点设置展开按钮.leaf也可以做到,但是要操作数据比较麻烦. 要实现懒加载模式下的模糊查询以及重新加载必须要使用data与laz ...

  3. Android 使用代码主动去调用控件的点击事件(模拟人手去触摸控件)

    使用代码主动去调用控件的点击事件(模拟人手去触摸控件) //View 可以是LinearLayout,Button,TextView View.performClick();

  4. easyui中tree控件添加自定义图标icon

    来源于:http://blog.163.com/lintianhuanhai@126/blog/static/165587366201421704420256/ <!DOCTYPE html&g ...

  5. DWZ (JUI) 教程 tree 控件的选中事件

    DWZ (JUI) 教程 tree 控件的选中事件 先简单说一下流程 第一步 当然是先定义好回调事件了 function checkCallback(json){ ........... ...... ...

  6. webdynpro tree控件使用

    1.  首先创建一个TREE控件 2.  在Tree下面创建一个TREE  NODE  TYPE ,node type 是可以继续展开的,而Item type是无法展开的. 3. 创建node.,下面 ...

  7. Kinect用体感来实现UI控件的点击

    用体感来实现UI控件的点击,如点击按钮. 做法:用一个图片表示左手手掌,图片位置追踪左手手掌移动,当手掌位于UI控件的矩形内时,握拳表示点击该控件. using UnityEngine; using ...

  8. UiAutomator2.0 - 控件实现点击操作原理

    目录 一.UiObject 二.UiObject2 穿梭各大技术博客网站,每天都能看到一些的新的技术.突然感觉UiAutomator 2.0相对于现在来说已经是个很久远的东西了ε=(´ο`*))).写 ...

  9. android中RecyclerView控件实现点击事件

    RecyclerView控件实现点击事件跟ListView控件不同,并没有提供类似setOnItemClickListener()这样的注册监听器方法,而是需要自己给子项具体的注册点击事件. 本文的例 ...

随机推荐

  1. 关于JPasswordField的getText()方法过时问题解决

    这几天想做一个登陆界面,用Jframe做,连接数据库时发现JPasswordField的getText()过时了,没法使用.查了资料发现改成了: try{ String sql="SELEC ...

  2. 使用 Nexus Repository Manager 搭建 npm 私服

    目录 环境 下载与安装 添加npm仓库 配置与验证npm仓库 发布自己的包 Nexus开启启动 脚注 环境 windows10(1803) Nexus Repository Manager OSS 3 ...

  3. 浅谈TCP IP协议栈(四)IP协议解析

    通过之前的网络层基础知识,IP地址以及路由器的简介,大家应该对于TCP/IP有一个大致的了解,在脑海里应该对于网络的几个基础概念有个大概的了解,简单点说整个协议栈就是在做一件事,规定网络报文(网络传输 ...

  4. 如何设置Oracle数据库客户端字符集以及系统中的NLS_LANG环境变量

    概述: 本地化是系统或软件运行的语言和文化环境.设置NLS_LANG环境参数是规定Oracle数据库软件本地化行为最简单的方式. NLS_LANG参数不但指定了客户端应用程序和Oracle数据库所使用 ...

  5. LeetCode算法题-Baseball Game(Java实现)

    这是悦乐书的第288次更新,第305篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第156题(顺位题号是682).你现在是棒球比赛点记录器.给定一个字符串列表,每个字符串 ...

  6. docker compose 服务启动顺序控制

    概要 docker-compose 可以方便组合多个 docker 容器服务, 但是, 当容器服务之间存在依赖关系时, docker-compose 并不能保证服务的启动顺序. docker-comp ...

  7. 我的第一个python web开发框架(26)——定制ORM(二)

    弄完底层数据库操作模块后,接下来要做的是ORM的正式设计.在开始之前,我们需要思考一下怎么来设计一个ORM呢?这个类它能帮助我们处理什么样的问题?需要有哪些功能模块?怎么做到针对不同的数据库与表单进行 ...

  8. 用Angular部署Cesium

    用到的集成开发环境是WebStrom,Cesium版本是1.50.0,Angular版本是6.2.4  1.首先我们安装cesium,在webstorm中的Termianl中输入 npm instal ...

  9. jsplumb 中文基础教程

    jsplumb 中文基础教程 https://github.com/wangduanduan/jsplumb-chinese-tutorial

  10. python小白——进阶之路——day3天-———运算符

    (1)算数运算符:  + - * / // % ** (2)比较运算符:  > < >= <= == != (3)赋值运算符:  = += -= *= /= //= %= ** ...