Tree 树形控件

多层次的结构列表。

何时使用

文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用 树控件 可以完整展现其中的层级关系,并具有展开收起选择等交互功能。

代码演示

基本

最简单的用法,展示可勾选,可选中,禁用,默认展开等功能。

Tree树形控件 - 图1

  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Tree } from 'choerodon-ui';
  4. const TreeNode = Tree.TreeNode;
  5. class Demo extends React.Component {
  6. onSelect = (selectedKeys, info) => {
  7. console.log('selected', selectedKeys, info);
  8. };
  9. onCheck = (checkedKeys, info) => {
  10. console.log('onCheck', checkedKeys, info);
  11. };
  12. render() {
  13. return (
  14. <Tree
  15. checkable
  16. defaultExpandedKeys={['0-0-0', '0-0-1']}
  17. defaultSelectedKeys={['0-0-0', '0-0-1']}
  18. defaultCheckedKeys={['0-0-0', '0-0-1']}
  19. onSelect={this.onSelect}
  20. onCheck={this.onCheck}
  21. >
  22. <TreeNode title="parent 1" key="0-0">
  23. <TreeNode title="parent 1-0" key="0-0-0" disabled>
  24. <TreeNode title="leaf" key="0-0-0-0" disableCheckbox />
  25. <TreeNode title="leaf" key="0-0-0-1" />
  26. </TreeNode>
  27. <TreeNode title="parent 1-1" key="0-0-1">
  28. <TreeNode title={<span style={{ color: '#1890ff' }}>sss</span>} key="0-0-1-0" />
  29. </TreeNode>
  30. </TreeNode>
  31. </Tree>
  32. );

受控操作示例

受控操作示例

Tree树形控件 - 图2

  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Tree } from 'choerodon-ui';
  4. const TreeNode = Tree.TreeNode;
  5. const treeData = [
  6. {
  7. title: '0-0',
  8. key: '0-0',
  9. children: [
  10. {
  11. title: '0-0-0',
  12. key: '0-0-0',
  13. children: [
  14. { title: '0-0-0-0', key: '0-0-0-0' },
  15. { title: '0-0-0-1', key: '0-0-0-1' },
  16. { title: '0-0-0-2', key: '0-0-0-2' },
  17. ],
  18. },
  19. {
  20. title: '0-0-1',
  21. key: '0-0-1',
  22. children: [
  23. { title: '0-0-1-0', key: '0-0-1-0' },
  24. { title: '0-0-1-1', key: '0-0-1-1' },
  25. { title: '0-0-1-2', key: '0-0-1-2' },
  26. ],
  27. },
  28. {
  29. title: '0-0-2',
  30. key: '0-0-2',
  31. },
  32. ],
  33. },
  34. {
  35. title: '0-1',
  36. key: '0-1',
  37. children: [
  38. { title: '0-1-0-0', key: '0-1-0-0' },
  39. { title: '0-1-0-1', key: '0-1-0-1' },
  40. { title: '0-1-0-2', key: '0-1-0-2' },
  41. ],
  42. },

拖动示例

将节点拖拽到其他节点内部或前后。

Tree树形控件 - 图3

  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Tree } from 'choerodon-ui';
  4. const TreeNode = Tree.TreeNode;
  5. const x = 3;
  6. const y = 2;
  7. const z = 1;
  8. const gData = [];
  9. const generateData = (_level, _preKey, _tns) => {
  10. const preKey = _preKey || '0';
  11. const tns = _tns || gData;
  12. const children = [];
  13. for (let i = 0; i < x; i++) {
  14. const key = `${preKey}-${i}`;
  15. tns.push({ title: key, key });
  16. if (i < y) {
  17. children.push(key);
  18. }
  19. }
  20. if (_level < 0) {
  21. return tns;
  22. }
  23. const level = _level - 1;
  24. children.forEach((key, index) => {
  25. tns[index].children = [];
  26. return generateData(level, key, tns[index].children);
  27. });
  28. };
  29. generateData(z);
  30. class Demo extends React.Component {
  31. state = {
  32. gData,
  33. expandedKeys: ['0-0', '0-0-0', '0-0-0-0'],
  34. };

异步数据加载

点击展开节点,动态加载数据。

Tree树形控件 - 图4

  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Tree } from 'choerodon-ui';
  4. const TreeNode = Tree.TreeNode;
  5. class Demo extends React.Component {
  6. state = {
  7. treeData: [
  8. { title: 'Expand to load', key: '0' },
  9. { title: 'Expand to load', key: '1' },
  10. { title: 'Tree Node', key: '2', isLeaf: true },
  11. ],
  12. };
  13. onLoadData = treeNode => {
  14. return new Promise(resolve => {
  15. if (treeNode.props.children) {
  16. resolve();
  17. return;
  18. }
  19. setTimeout(() => {
  20. treeNode.props.dataRef.children = [
  21. { title: 'Child Node', key: `${treeNode.props.eventKey}-0` },
  22. { title: 'Child Node', key: `${treeNode.props.eventKey}-1` },
  23. ];
  24. this.setState({
  25. treeData: [...this.state.treeData],
  26. });
  27. resolve();
  28. }, 1000);
  29. });
  30. };
  31. renderTreeNodes = data => {
  32. return data.map(item => {
  33. if (item.children) {
  34. return (
  35. <TreeNode title={item.title} key={item.key} dataRef={item}>
  36. {this.renderTreeNodes(item.children)}

可搜索

可搜索的树。

Tree树形控件 - 图5

  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Tree, Input } from 'choerodon-ui';
  4. const TreeNode = Tree.TreeNode;
  5. const Search = Input.Search;
  6. const x = 3;
  7. const y = 2;
  8. const z = 1;
  9. const gData = [];
  10. const generateData = (_level, _preKey, _tns) => {
  11. const preKey = _preKey || '0';
  12. const tns = _tns || gData;
  13. const children = [];
  14. for (let i = 0; i < x; i++) {
  15. const key = `${preKey}-${i}`;
  16. tns.push({ title: key, key });
  17. if (i < y) {
  18. children.push(key);
  19. }
  20. }
  21. if (_level < 0) {
  22. return tns;
  23. }
  24. const level = _level - 1;
  25. children.forEach((key, index) => {
  26. tns[index].children = [];
  27. return generateData(level, key, tns[index].children);
  28. });
  29. };

目录

内置的目录树,multiple 模式支持 ctrl(Windows) / command(Mac) 复选。

Tree树形控件 - 图6

  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Tree } from 'choerodon-ui';
  4. const { DirectoryTree } = Tree;
  5. const treeData = [
  6. {
  7. title: 'parent 0',
  8. key: '0-0',
  9. children: [
  10. { title: 'leaf 0-0', key: '0-0-0', isLeaf: true },
  11. { title: 'leaf 0-1', key: '0-0-1', isLeaf: true },
  12. ],
  13. },
  14. {
  15. title: 'parent 1',
  16. key: '0-1',
  17. children: [
  18. { title: 'leaf 1-0', key: '0-1-0', isLeaf: true },
  19. { title: 'leaf 1-1', key: '0-1-1', isLeaf: true },
  20. ],
  21. },
  22. ];
  23. const App = () => {
  24. const onSelect = (keys, event) => {
  25. console.log('Trigger Select', keys, event);
  26. };
  27. const onExpand = () => {
  28. console.log('Trigger Expand');
  29. };
  30. return (
  31. <DirectoryTree

虚拟滚动

使用 height 属性则切换为虚拟滚动。

Tree树形控件 - 图7

  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Tree } from 'choerodon-ui';
  4. function dig(path = '0', level = 3) {
  5. const list = [];
  6. for (let i = 0; i < 10; i += 1) {
  7. const key = `${path}-${i}`;
  8. const treeNode = {
  9. title: key,
  10. key,
  11. };
  12. if (level > 0) {
  13. treeNode.children = dig(key, level - 1);
  14. }
  15. list.push(treeNode);
  16. }
  17. return list;
  18. }
  19. const treeData = dig();
  20. ReactDOM.render(<Tree checkable treeData={treeData} height={233} defaultExpandAll />, document.getElementById('container'));

API

Tree props

参数说明类型默认值
autoExpandParent是否自动展开父节点booleantrue
blockNode是否节点占据一行booleanfalse
checkable节点前添加 Checkbox 复选框booleanfalse
checkedKeys(受控)选中复选框的树节点(注意:父子节点有关联,如果传入父节点 key,则子节点自动选中;相应当子节点 key 都传入,父节点也自动选中。当设置checkablecheckStrictly,它是一个有checkedhalfChecked属性的对象,并且父子节点的选中与否不再关联string[] | {checked: string[], halfChecked: string[]}[]
checkStrictlycheckable 状态下节点选择完全受控(父子节点选中状态不再关联)booleanfalse
defaultCheckedKeys默认选中复选框的树节点string[][]
defaultExpandAll默认展开所有树节点booleanfalse
defaultExpandedKeys默认展开指定的树节点string[][]
defaultExpandParent默认展开父节点booltrue
defaultSelectedKeys默认选中的树节点string[][]
disabled将树禁用boolfalse
draggable设置节点可拖拽(IE>8)booleanfalse
expandedKeys(受控)展开指定的树节点string[][]
filterTreeNode按需筛选树节点(高亮),返回 truefunction(node)-
loadData异步加载数据function(node)-
loadedKeys(受控)已经加载的节点,需要配合 loadData 使用string[][]
multiple支持点选多个节点(节点本身)booleanfalse
selectable是否可选中booleantrue
selectedKeys(受控)设置选中的树节点string[]-
showIcon是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式booleanfalse
switcherIcon自定义树节点的展开/折叠图标React.ReactElement-
showLine是否展示连接线booleanfalse
onCheck点击复选框触发function(checkedKeys, e:{checked: bool, checkedNodes, node, event, halfCheckedKeys})-
onDragEnddragend 触发时调用function({event, node})-
onDragEnterdragenter 触发时调用function({event, node, expandedKeys})-
onDragLeavedragleave 触发时调用function({event, node})-
onDragOverdragover 触发时调用function({event, node})-
onDragStart开始拖拽时调用function({event, node})-
onDropdrop 触发时调用function({event, node, dragNode, dragNodesKeys})-
onExpand展开/收起节点时触发function(expandedKeys, {expanded: bool, node})-
onLoad节点加载完毕时触发function(loadedKeys, {event, node})-
onRightClick响应右键点击function({event, node})-
onSelect点击树节点触发function(selectedKeys, e:{selected: bool, selectedNodes, node, event})-
treeDatatreeNodes 数据,如果设置则不需要手动构造 TreeNode 节点(key 在整个树范围内唯一)array<{key, title, children, [disabled, selectable]}>-

TreeNode props

参数说明类型默认值
checkable当树为 checkable 时,设置独立节点是否展示 Checkboxboolean-
disableCheckbox禁掉 checkboxbooleanfalse
disabled禁掉响应booleanfalse
icon自定义图标。可接收组件,props 为当前节点 propsReactNode/Function(props):ReactNode-
isLeaf设置为叶子节点(设置了loadData时有效)booleanfalse
key被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意:整个树范围内的所有节点的 key 值不能重复!string内部计算出的节点位置
selectable设置节点是否可被选中booleantrue
title标题string|ReactNode‘—-‘

DirectoryTree props

参数说明类型默认值
expandAction目录展开逻辑,可选 false ‘click’ ‘doubleClick’stringclick

注意

在之前:树节点可以有很多,但在设置checkable时,将会花费更多的计算时间,因此我们缓存了一些计算结果(this.treeNodesStates)来复用,避免多次重复计算,以此提高性能。但这也带来了一些限制,当你异步加载树节点时,你需要这样渲染树:

  1. {
  2. this.state.treeData.length ? (
  3. <Tree>
  4. {this.state.treeData.map(data => (
  5. <TreeNode />
  6. ))}
  7. </Tree>
  8. ) : (
  9. 'loading tree'
  10. );
  11. }

FAQ

在 showLine 时,如何隐藏子节点图标?

文件图标通过 switcherIcon 来实现,如果不需要你可以覆盖对应的样式:https://codesandbox.io/s/883vo47xp8

defaultExpandedAll 在异步加载数据时为何不生效?

default 前缀属性只有在初始化时生效,因而异步加载数据时 defaultExpandedAll 已经执行完成。你可以通过受控 expandedKeys 或者在数据加载完成后渲染 Tree 来实现全部展开。