Element UI 2x 级联选择器组件动态 option 属性导致的异常抛出

业务上遇到一个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-panelvalue,如果 el-cascader-panel 组件的 valuecheckedValue 不相等时则会去重置 activePath[]。所以可以通过修改 value 的方式来避免异常的抛出,但是一定要在 options 改变之前才行。

所以每次级联选择器 options 改变之前重置掉绑定的 value 值然就行,但是需要保证你业务代码的执行顺序,但很多时候我都是按照业务视图顺序的方式去书写代码,所以得调整一些赋值操作的前后循序。以及需要去放弃使用 v-model 转而使用 @change 去手动赋值和修改修改 options

总而言之直接给级联选择器设置 key 依旧是是一个简单高效的方式,除非说当前的业务十分复杂并且需要考虑性能问题的情况。

以上


相关阅读

Cascader 级联选择器 - 组件 | Element
element/cascader-panel.vue at v2.15.13 · ElemeFE/element

el-cascader的使用以及报错解决_大橙子额的博客