树形控件

何时使用

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

代码演示

Tree树形控件 - 图1

受控操作示例

受控操作示例

  1. <template>
  2. <a-tree
  3. checkable
  4. @expand="onExpand"
  5. :expandedKeys="expandedKeys"
  6. :autoExpandParent="autoExpandParent"
  7. v-model="checkedKeys"
  8. @select="onSelect"
  9. :selectedKeys="selectedKeys"
  10. :treeData="treeData"
  11. />
  12. </template>
  13. <script>
  14. const treeData = [{
  15. title: '0-0',
  16. key: '0-0',
  17. children: [{
  18. title: '0-0-0',
  19. key: '0-0-0',
  20. children: [
  21. { title: '0-0-0-0', key: '0-0-0-0' },
  22. { title: '0-0-0-1', key: '0-0-0-1' },
  23. { title: '0-0-0-2', key: '0-0-0-2' },
  24. ],
  25. }, {
  26. title: '0-0-1',
  27. key: '0-0-1',
  28. children: [
  29. { title: '0-0-1-0', key: '0-0-1-0' },
  30. { title: '0-0-1-1', key: '0-0-1-1' },
  31. { title: '0-0-1-2', key: '0-0-1-2' },
  32. ],
  33. }, {
  34. title: '0-0-2',
  35. key: '0-0-2',
  36. }],
  37. }, {
  38. title: '0-1',
  39. key: '0-1',
  40. children: [
  41. { title: '0-1-0-0', key: '0-1-0-0' },
  42. { title: '0-1-0-1', key: '0-1-0-1' },
  43. { title: '0-1-0-2', key: '0-1-0-2' },
  44. ],
  45. }, {
  46. title: '0-2',
  47. key: '0-2',
  48. }]
  49. export default {
  50. data () {
  51. return {
  52. expandedKeys: ['0-0-0', '0-0-1'],
  53. autoExpandParent: true,
  54. checkedKeys: ['0-0-0'],
  55. selectedKeys: [],
  56. treeData,
  57. }
  58. },
  59. watch: {
  60. checkedKeys(val) {
  61. console.log('onCheck', val)
  62. }
  63. },
  64. methods: {
  65. onExpand (expandedKeys) {
  66. console.log('onExpand', expandedKeys)
  67. // if not set autoExpandParent to false, if children expanded, parent can not collapse.
  68. // or, you can remove all expanded children keys.
  69. this.expandedKeys = expandedKeys
  70. this.autoExpandParent = false
  71. },
  72. onCheck (checkedKeys) {
  73. console.log('onCheck', checkedKeys)
  74. this.checkedKeys = checkedKeys
  75. },
  76. onSelect (selectedKeys, info) {
  77. console.log('onSelect', info)
  78. this.selectedKeys = selectedKeys
  79. },
  80. },
  81. }
  82. </script>

Tree树形控件 - 图2

基本用法

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

  1. <template>
  2. <a-tree
  3. checkable
  4. :treeData="treeData"
  5. :defaultExpandedKeys="['0-0-0', '0-0-1']"
  6. :defaultSelectedKeys="['0-0-0', '0-0-1']"
  7. :defaultCheckedKeys="['0-0-0', '0-0-1']"
  8. @select="this.onSelect"
  9. @check="this.onCheck"
  10. >
  11. <span slot="title0010" style="color: #1890ff">sss</span>
  12. </a-tree>
  13. </template>
  14. <script>
  15. const treeData = [{
  16. title: 'parent 1',
  17. key: '0-0',
  18. children: [{
  19. title: 'parent 1-0',
  20. key: '0-0-0',
  21. disabled: true,
  22. children: [
  23. { title: 'leaf', key: '0-0-0-0', disableCheckbox: true },
  24. { title: 'leaf', key: '0-0-0-1' },
  25. ],
  26. }, {
  27. title: 'parent 1-1',
  28. key: '0-0-1',
  29. children: [
  30. { key: '0-0-1-0', slots: { title: 'title0010' }},
  31. ],
  32. }],
  33. }]
  34. export default {
  35. data () {
  36. return {
  37. treeData,
  38. }
  39. },
  40. methods: {
  41. onSelect (selectedKeys, info) {
  42. console.log('selected', selectedKeys, info)
  43. },
  44. onCheck (checkedKeys, info) {
  45. console.log('onCheck', checkedKeys, info)
  46. },
  47. },
  48. }
  49. </script>

Tree树形控件 - 图3

自定义图标

可以针对不同的节点定制图标。

  1. <template>
  2. <a-tree
  3. :treeData="treeData"
  4. showIcon
  5. defaultExpandAll
  6. :defaultSelectedKeys="['0-0-0']"
  7. >
  8. <a-icon slot="smile" type="smile-o" />
  9. <a-icon slot="meh" type="smile-o" />
  10. <template slot="custom" slot-scope="{selected}">
  11. <a-icon :type="selected ? 'frown':'frown-o'" />
  12. </template>
  13. </a-tree>
  14. </template>
  15. <script>
  16. const treeData = [{
  17. title: 'parent 1',
  18. key: '0-0',
  19. slots: {
  20. icon: 'smile',
  21. },
  22. children: [
  23. { title: 'leaf', key: '0-0-0', slots: { icon: 'meh' }},
  24. { title: 'leaf', key: '0-0-1', scopedSlots: { icon: 'custom' }}],
  25. }]
  26. export default {
  27. data () {
  28. return {
  29. treeData,
  30. }
  31. },
  32. methods: {
  33. onSelect (selectedKeys, info) {
  34. console.log('selected', selectedKeys, info)
  35. },
  36. onCheck (checkedKeys, info) {
  37. console.log('onCheck', checkedKeys, info)
  38. },
  39. },
  40. }
  41. </script>

Tree树形控件 - 图4

拖动示例

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

  1. <template>
  2. <a-tree
  3. class="draggable-tree"
  4. :defaultExpandedKeys="expandedKeys"
  5. draggable
  6. @dragenter="onDragEnter"
  7. @drop="onDrop"
  8. :treeData="gData"
  9. />
  10. </template>
  11. <script>
  12. const x = 3
  13. const y = 2
  14. const z = 1
  15. const gData = []
  16. const generateData = (_level, _preKey, _tns) => {
  17. const preKey = _preKey || '0'
  18. const tns = _tns || gData
  19. const children = []
  20. for (let i = 0; i < x; i++) {
  21. const key = `${preKey}-${i}`
  22. tns.push({ title: key, key })
  23. if (i < y) {
  24. children.push(key)
  25. }
  26. }
  27. if (_level < 0) {
  28. return tns
  29. }
  30. const level = _level - 1
  31. children.forEach((key, index) => {
  32. tns[index].children = []
  33. return generateData(level, key, tns[index].children)
  34. })
  35. }
  36. generateData(z)
  37. export default {
  38. data () {
  39. return {
  40. gData,
  41. expandedKeys: ['0-0', '0-0-0', '0-0-0-0'],
  42. }
  43. },
  44. methods: {
  45. onDragEnter (info) {
  46. console.log(info)
  47. // expandedKeys 需要受控时设置
  48. // this.expandedKeys = info.expandedKeys
  49. },
  50. onDrop (info) {
  51. console.log(info)
  52. const dropKey = info.node.eventKey
  53. const dragKey = info.dragNode.eventKey
  54. const dropPos = info.node.pos.split('-')
  55. const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
  56. const loop = (data, key, callback) => {
  57. data.forEach((item, index, arr) => {
  58. if (item.key === key) {
  59. return callback(item, index, arr)
  60. }
  61. if (item.children) {
  62. return loop(item.children, key, callback)
  63. }
  64. })
  65. }
  66. const data = [...this.gData]
  67. // Find dragObject
  68. let dragObj
  69. loop(data, dragKey, (item, index, arr) => {
  70. arr.splice(index, 1)
  71. dragObj = item
  72. })
  73. if (!info.dropToGap) {
  74. // Drop on the content
  75. loop(data, dropKey, (item) => {
  76. item.children = item.children || [];
  77. // where to insert 示例添加到尾部,可以是随意位置
  78. item.children.push(dragObj);
  79. });
  80. } else if (
  81. (info.node.children || []).length > 0 // Has children
  82. && info.node.expanded // Is expanded
  83. && dropPosition === 1 // On the bottom gap
  84. ) {
  85. loop(data, dropKey, (item) => {
  86. item.children = item.children || [];
  87. // where to insert 示例添加到尾部,可以是随意位置
  88. item.children.unshift(dragObj);
  89. });
  90. } else {
  91. let ar;
  92. let i;
  93. loop(data, dropKey, (item, index, arr) => {
  94. ar = arr;
  95. i = index;
  96. });
  97. if (dropPosition === -1) {
  98. ar.splice(i, 0, dragObj);
  99. } else {
  100. ar.splice(i + 1, 0, dragObj);
  101. }
  102. }
  103. this.gData = data
  104. },
  105. },
  106. }
  107. </script>

Tree树形控件 - 图5

异步数据加载

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

  1. <template>
  2. <a-tree
  3. :loadData="onLoadData"
  4. :treeData="treeData"
  5. />
  6. </template>
  7. <script>
  8. export default {
  9. data () {
  10. return {
  11. treeData: [
  12. { title: 'Expand to load', key: '0' },
  13. { title: 'Expand to load', key: '1' },
  14. { title: 'Tree Node', key: '2', isLeaf: true },
  15. ],
  16. }
  17. },
  18. methods: {
  19. onLoadData (treeNode) {
  20. return new Promise((resolve) => {
  21. if (treeNode.dataRef.children) {
  22. resolve()
  23. return
  24. }
  25. setTimeout(() => {
  26. treeNode.dataRef.children = [
  27. { title: 'Child Node', key: `${treeNode.eventKey}-0` },
  28. { title: 'Child Node', key: `${treeNode.eventKey}-1` },
  29. ]
  30. this.treeData = [...this.treeData]
  31. resolve()
  32. }, 1000)
  33. })
  34. },
  35. },
  36. }
  37. </script>

Tree树形控件 - 图6

连接线

带连接线的树。

  1. <template>
  2. <a-tree
  3. showLine
  4. :defaultExpandedKeys="['0-0-0']"
  5. @select="onSelect"
  6. >
  7. <a-tree-node key="0-0">
  8. <span slot="title" style="color: #1890ff">parent 1</span>
  9. <a-tree-node title="parent 1-0" key="0-0-0">
  10. <a-tree-node title="leaf" key="0-0-0-0" />
  11. <a-tree-node title="leaf" key="0-0-0-1" />
  12. <a-tree-node title="leaf" key="0-0-0-2" />
  13. </a-tree-node>
  14. <a-tree-node title="parent 1-1" key="0-0-1">
  15. <a-tree-node title="leaf" key="0-0-1-0" />
  16. </a-tree-node>
  17. <a-tree-node title="parent 1-2" key="0-0-2">
  18. <a-tree-node title="leaf" key="0-0-2-0" />
  19. <a-tree-node title="leaf" key="0-0-2-1" />
  20. </a-tree-node>
  21. </a-tree-node>
  22. </a-tree>
  23. </template>
  24. <script>
  25. export default {
  26. methods: {
  27. onSelect (selectedKeys, info) {
  28. console.log('selected', selectedKeys, info)
  29. },
  30. },
  31. }
  32. </script>

Tree树形控件 - 图7

可搜索

可搜索的树。

  1. <template>
  2. <div>
  3. <a-input-search style="margin-bottom: 8px" placeholder="Search" @change="onChange" />
  4. <a-tree
  5. @expand="onExpand"
  6. :expandedKeys="expandedKeys"
  7. :autoExpandParent="autoExpandParent"
  8. :treeData="gData"
  9. >
  10. <template slot="title" slot-scope="{title}">
  11. <span v-if="title.indexOf(searchValue) > -1">
  12. {{title.substr(0, title.indexOf(searchValue))}}
  13. <span style="color: #f50">{{searchValue}}</span>
  14. {{title.substr(title.indexOf(searchValue) + searchValue.length)}}
  15. </span>
  16. <span v-else>{{title}}</span>
  17. </template>
  18. </a-tree>
  19. </div>
  20. </template>
  21. <script>
  22. const x = 3
  23. const y = 2
  24. const z = 1
  25. const gData = []
  26. const generateData = (_level, _preKey, _tns) => {
  27. const preKey = _preKey || '0'
  28. const tns = _tns || gData
  29. const children = []
  30. for (let i = 0; i < x; i++) {
  31. const key = `${preKey}-${i}`
  32. tns.push({ title: key, key, scopedSlots: { title: 'title' }})
  33. if (i < y) {
  34. children.push(key)
  35. }
  36. }
  37. if (_level < 0) {
  38. return tns
  39. }
  40. const level = _level - 1
  41. children.forEach((key, index) => {
  42. tns[index].children = []
  43. return generateData(level, key, tns[index].children)
  44. })
  45. }
  46. generateData(z)
  47. const dataList = []
  48. const generateList = (data) => {
  49. for (let i = 0; i < data.length; i++) {
  50. const node = data[i]
  51. const key = node.key
  52. dataList.push({ key, title: key })
  53. if (node.children) {
  54. generateList(node.children, node.key)
  55. }
  56. }
  57. }
  58. generateList(gData)
  59. const getParentKey = (key, tree) => {
  60. let parentKey
  61. for (let i = 0; i < tree.length; i++) {
  62. const node = tree[i]
  63. if (node.children) {
  64. if (node.children.some(item => item.key === key)) {
  65. parentKey = node.key
  66. } else if (getParentKey(key, node.children)) {
  67. parentKey = getParentKey(key, node.children)
  68. }
  69. }
  70. }
  71. return parentKey
  72. }
  73. export default {
  74. data () {
  75. return {
  76. expandedKeys: [],
  77. searchValue: '',
  78. autoExpandParent: true,
  79. gData,
  80. }
  81. },
  82. methods: {
  83. onExpand (expandedKeys) {
  84. this.expandedKeys = expandedKeys
  85. this.autoExpandParent = false
  86. },
  87. onChange (e) {
  88. const value = e.target.value
  89. const expandedKeys = dataList.map((item) => {
  90. if (item.key.indexOf(value) > -1) {
  91. return getParentKey(item.key, gData)
  92. }
  93. return null
  94. }).filter((item, i, self) => item && self.indexOf(item) === i)
  95. Object.assign(this, {
  96. expandedKeys,
  97. searchValue: value,
  98. autoExpandParent: true,
  99. })
  100. },
  101. },
  102. }
  103. </script>

Tree树形控件 - 图8

目录

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

  1. <template>
  2. <a-directory-tree
  3. multiple
  4. defaultExpandAll
  5. @select="onSelect"
  6. @expand="onExpand"
  7. >
  8. <a-tree-node title="parent 0" key="0-0">
  9. <a-tree-node title="leaf 0-0" key="0-0-0" isLeaf />
  10. <a-tree-node title="leaf 0-1" key="0-0-1" isLeaf />
  11. </a-tree-node>
  12. <a-tree-node title="parent 1" key="0-1">
  13. <a-tree-node title="leaf 1-0" key="0-1-0" isLeaf />
  14. <a-tree-node title="leaf 1-1" key="0-1-1" isLeaf />
  15. </a-tree-node>
  16. </a-directory-tree>
  17. </template>
  18. <script>
  19. export default {
  20. methods: {
  21. onSelect (keys) {
  22. console.log('Trigger Select', keys);
  23. },
  24. onExpand () {
  25. console.log('Trigger Expand');
  26. },
  27. },
  28. }
  29. </script>

API

Tree props

参数说明类型默认值
treeData节点的配置描述,具体项见下表, 1.1.4之前的版本使用treeNodesarray
autoExpandParent是否自动展开父节点booleantrue
checkable节点前添加 Checkbox 复选框booleanfalse
checkedKeys(v-model)(受控)选中复选框的树节点(注意:父子节点有关联,如果传入父节点key,则子节点自动选中;相应当子节点key都传入,父节点也自动选中。当设置checkablecheckStrictly,它是一个有checkedhalfChecked属性的对象,并且父子节点的选中与否不再关联string[] | number[] | {checked: string[] | number[], halfChecked: string[] | number[]}[]
checkStrictlycheckable状态下节点选择完全受控(父子节点选中状态不再关联)booleanfalse
defaultCheckedKeys默认选中复选框的树节点string[] | number[][]
defaultExpandAll默认展开所有树节点booleanfalse
defaultExpandedKeys默认展开指定的树节点string[] | number[][]
defaultExpandParent默认展开父节点booltrue
defaultSelectedKeys默认选中的树节点string[] | number[][]
disabled将树禁用boolfalse
draggable设置节点可拖拽booleanfalse
expandedKeys(.sync)(受控)展开指定的树节点string[] | number[][]
filterTreeNode按需筛选树节点(高亮),返回truefunction(node)-
loadData异步加载数据function(node)-
loadedKeys(受控)已经加载的节点,需要配合 loadData 使用string[] | number[][]
multiple支持点选多个节点(节点本身)booleanfalse
selectedKeys(.sync)(受控)设置选中的树节点string[] | number[]-
showIcon是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式booleanfalse
showLine是否展示连接线booleanfalse

事件

事件名称说明回调参数
check点击复选框触发function(checkedKeys, e:{checked: bool, checkedNodes, node, event})
dragenddragend 触发时调用function({event, node})
dragenterdragenter 触发时调用function({event, node, expandedKeys})
dragleavedragleave 触发时调用function({event, node})
dragoverdragover 触发时调用function({event, node})
dragstart开始拖拽时调用function({event, node})
dropdrop 触发时调用function({event, node, dragNode, dragNodesKeys})
expand展开/收起节点时触发function(expandedKeys, {expanded: bool, node})
load节点加载完毕时触发function(loadedKeys, {event, node})
rightClick响应右键点击function({event, node})
select点击树节点触发function(selectedKeys, e:{selected: bool, selectedNodes, node, event})

TreeNode props

结点描述数据对象,是 treeNodes 中的一项,TreeNode 使用相同的 API。

参数说明类型默认值
class节点的 classstring-
style节点的 stylestring|object-
disableCheckbox禁掉 checkboxbooleanfalse
disabled禁掉响应booleanfalse
icon自定义图标。可接收组件,props 为当前节点 propsslot|slot-scope-
isLeaf设置为叶子节点(设置了loadData时有效)booleanfalse
key被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意:整个树范围内的所有节点的 key 值不能重复!string | number内部计算出的节点位置
selectable设置节点是否可被选中booleantrue
title标题string|slot|slot-scope'—-'
slots使用treeNodes时,可以通过该属性配置支持slot的属性,如 slots: { title: 'XXX'}object-
scopedSlots使用columns时,可以通过该属性配置支持slot-scope的属性,如 scopedSlots: { title: 'XXX'}object-
on事件对象,仅在treeNodes使用方式中生效,如{click: () => {}}object'—-'

DirectoryTree props

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