antd-vue树形控件实现默认展开全部节点
背景分析解决方案树形控件官方文档
版本信息:
"vue":"2.6.11""ant-design-vue": "1.7.0""vuex": "3.1.1"
背景
在做项目的时候遇到需要默认选中和展开所有节点的需求。
自动选中所有节点
a-tree
的v-model
默认就是checkedKeys
,因此默认选中所有节点(父节点和子节点),只要在created
周期钩子里将checkedKeys
初始化成所有子节点就好了。自动展开所有节点:
defaultExpandAll
这个属性似乎无效,于是乎尝试在created
周期里初始化defaultExpandedKeys
为所有节点。
于是乎html部分这样写
...<a-spin :spinning="treeOnLoad" style="height:200px;"><a-treev-model="checkedKeys"checkable:tree-data="teamTreeWithCarCount":defaultExpandedKeys="expandedKeys"/></a-spin>...
js部分的created
周期函数这样写:
async created () {...// 树的获取await this.getTeamTreeWithCarCount() // 获取树节点信息的函数this.checkedKeys = this.teamTreeList // this.teamList在computed中将树节点平铺开而成this.defaultExpandedKeys = this.teamTreeList // 默认展开全部节点this.treeOnLoad = false...}
结果并没有自动展开…
分析
首先分析生命周期问题:父组件(即当前组件,称为A),子组件(a-tree组件,称为B)。
B作为A的子组件,执行顺序应该为:A beforeCreate
->A created
,此时A的props,methods, data 和 computed 都初始化完毕,然后在A created
生命周期,发送获取树节点的axios请求。这之后编译好模板字符串,进入A beforeMount
,挂载过程中发现需要渲染子组件,然后进行子组件的构建:B beforeCreate
,B created
,B beforeMount
,B mounted
,等待所有子组件加载完毕,进入A mounted
。
总结一下,就是A beforeCreate
->A created
->A beforeMount
->B beforeCreate
->B created
->B beforeMount
->B mounted
->A mounted
。
按照这个逻辑,会有两个问题:B mounted
在A created
之后,那么A中的expandedKeys
应该会被渲染进B的defaultExpandedKeys
里呀?就算在B mounted
结束之后,B中的defaultExpandedKeys
还没有得到正确的数据,那么后续A中的expandedKeys
拿到了,难道不会触发B beforeUpdate
生命周期么?那这样还是会展开所有的节点呀?
生命周期钩子的异步
针对第一个问题,需要弄明白一个概念,生命周期钩子本质上是函数,如果把它写成async
函数,它就成了异步函数,它是不会阻塞后面生命周期的执行的。
以A created
为例,在这个生命周期函数里,我们执行了这个语句:
await this.getTeamTreeWithCarCount() // 获取树节点信息的函数
但这个await
语句只会阻塞created
函数内后续语句的执行,不应该created
函数外部同步语句的执行,也就是不阻塞vue后续的生命周期的进行。
所以,当A beforeCreate
->A created
->A beforeMount
->B beforeCreate
->B created
->B beforeMount
->B mounted
->A mounted
这个流程走完之后,axios
异步返回的结果才会作用到页面上,引发A beforeUpdate
->B beforeUpdate
->B updated
->A updated
。
至此就解释了为什么子组件B直到mounted
阶段都不会被父组件Aaxios
返回的数据初始化。
defaultExpandedKeys 本身就是一锤子买卖
针对第二个问题,后续返回的树节点数据为什么不会被更新到子组件A的defaultExpandedKeys
上呢?这是因为defaultExpandedKeys
的设计初衷本就不是动态变化的,可以看下官方的示例:
带default
字样的属性本身就是写死的值
,或者严谨点,匿名变量
,而不是一个可更改的变量
。
因此,defaultExpandedKeys
在初始化之后,再去更改它是没有作用的。
解决方案
可以通过完全操控a-tree
的expandedKeys
来实现默认全部展开的效果。
html代码如下:
<a-spin :spinning="treeOnLoad" style="height:200px;"><a-treev-model="checkedKeys"checkable:defaultExpandParent="true":tree-data="teamTreeWithCarCount":expandedKeys.sync="defaultExpandedKeys":defaultExpandAll="true"/></a-spin>
注意expandedKeys
需要使用.sync
修饰符,否则子组件a-tree
无法修改defaultExpandedKeys
,就无法进行正常的勾选了。
然后在JS部分还是一样:
async created () {...// 树的获取await this.getTeamTreeWithCarCount() // 获取树节点信息的函数this.checkedKeys = this.teamTreeList // this.teamList在computed中将树节点平铺开而成this.defaultExpandedKeys = this.teamTreeList // 默认展开全部节点this.treeOnLoad = false...}