业务上遇到一个UI的变更需求,要求是把一个 三层数据的级联选择器组件 拆分成 下拉选择组件 + 二层数据的级联选择器组件 的形式去展示。也就是把三层数据的第一层提出来赋值给下拉选择器组件,对应的二级三级数据依旧是在 级联选择组件 中选择。
需求其实很简单,也很快就处理掉了,但是自测的时候就总是会看到控制台会抛出一个异常:[Vue warn]: Error in callback for watcher "options": "TypeError: Cannot read property 'level' of null
因为在测试环境就下意识以为是因为测试的假数据对不上级联选择器可选项 value
造成的匹配不到对应的层级导致的报错,就没有过多的关注。今天开发完手头上的主体业务回过头来收尾细节的时候发现并不是这么一回事。
其实是由于 <el-cascader>
级联选择器的 options
属性被动态修改而造成的问题。
这边提前说一个简答解决方式:
给级联选择器增加
key
键,让每次options
修改时重新渲染组件即可。
一开始这个报错信息是在弹窗关闭的时候出现的,所以我就简单的认为是关闭弹窗时使用 resetFields()
方法的把表单绑定的 model
重置导致的,以前遇到过使用 resetFields()
重置表单会时表单数据失去响应。所以修改为了手动置空表单再使用 clearValidate
清理校验结果,但是问题依旧任然会抛出 TypeError: Cannot read property 'level' of null
的错误信息,所以并不是数据重置导致的异常。
又觉得可能是因为 el-caseader
组件的 value
需要是一个数组,重置完表单之后绑定的 value
会变成 undefined
所以修改手动置空表单是声明绑定的属性为 []
(病急乱投医),并无果。
在反复折腾一番确认使用 v-model
绑定的变量在弹窗组件关闭后没有被错误赋值之后,祭出了谷歌大法:
cascader
有选中项的绑定值checkedValue
和点击的父节点(高亮)activePath
, 即便设置了this.cascaderValue= []
,cascader
中的activePath
还是有值,也就是点击的父节点会被记录下来,再次加载cascader
找不到就会报错。
最后提到的解决方案是 给级联选择器增加 key
键,让每次 options
修改时都是一个新的组件来渲染,然后同时修改绑定的 value
值。这样就会确保不会出现有选择值或者高亮路径值导致无法匹配到 option
层级。
中间提到了两种方式我就不具体说了。单独说一下文章中提到的:修改 value
并不能根本解决问题的部分。
我看了一下当前版本(2.15.13
)的级联组件的源码部分,现在的级联选择器在 value
变更时会去同步修改 el-cascader-panel
的 value
,如果 el-cascader-panel
组件的 value
和 checkedValue
不相等时则会去重置 activePath
为 []
。所以可以通过修改 value
的方式来避免异常的抛出,但是一定要在 options
改变之前才行。
所以每次级联选择器 options
改变之前重置掉绑定的 value
值然就行,但是需要保证你业务代码的执行顺序,但很多时候我都是按照业务视图顺序的方式去书写代码,所以得调整一些赋值操作的前后循序。以及需要去放弃使用 v-model
转而使用 @change
去手动赋值和修改修改 options
。
总而言之直接给级联选择器设置 key
依旧是是一个简单高效的方式,除非说当前的业务十分复杂并且需要考虑性能问题的情况。
以上
相关阅读
Cascader 级联选择器 - 组件 | Element
element/cascader-panel.vue at v2.15.13 · ElemeFE/element