Hello 各位前端的小伙伴,你们好!
今天分享一篇关于 el-cascder(级联选择器) 组件的报错
关于 cascader 组件报错;Error in callback for watcher 'options': 'TypeError: Cannot read properties of null (reading 'level')'
报错信息
"[Vue warn]: Error in callback for watcher 'options': 'TypeError: Cannot read properties of null (reading 'level')'
需求:
名称为 select 组件;组织为 cascader 组件;均有可清空属性 clearable
目前的情况时,我用户选择 名称,然后拿到相关 名称 ID;然后请求 组织 数据;然后在给 组织 组件 传过去;改变 cascader 的 options;目前全部都是正常的;组织 和 名称 单独点击清空;无报错;直到 名称和组织 的组件上都选中数据,然后点击 名称的 清除(clearable),(组件 cascader 的数据 依赖于 select 数据;当 select 清空 cascader 数据也得清空);就产生了以上报错;
原因:
出现在syncActivePath函数中解构 activePath,此时的 activePath为上一次的选中的那么在getNodeByValue函数中获取到的是null,即 expandNodes的 nodes为 [null],那么在handleExpand中就出现null.level
我理解的意思就是,当用户选择了 cascader 组价中的数据时,会被打上高亮效果;选择的数据被储存在activePath中;当我切换依赖数据时,cascader 组件的 options 会被清空;然后 父组件 根据依赖的数据再次请求 cascader 的数据,并传递给 cascader 组件的options; 再次触发 cascader 组件,但是上次选中的 activePath没有被清空,所以他在 本次数据的 options 中 找上次的高亮的数据;没有找到;所以会有以上报错;
解决方案:
-
让 cascader 组件 重新渲染(不推荐组件重新渲染,消耗性能)
-
key 方式
-
v-if 方式
并且结合我的需求会发现 加 key 的方式重新渲染 cascader 组件;会渲染两次;当父组件 开始请求数据时 ,会将 cascader 的 options 置空,options 发生改变,cascader 组件会重新渲染;父组件请求到数据并传递给 cascader 组件的 options 时,又重新渲染一次;这个过程用户可以清楚的看到
<template> <sec-cascader :key="casacderKey" ref="cascader" v-model="value" class="cascader" placeholder="请选择" :options="options" clearable :show-all-levels="true" filterable :props="{ expandTrigger: 'click', multiple: false, checkStrictly: true }" @change="handleChange" ></sec-cascader> </template> <script> export default { name: 'Cascader', props: { options: { type: Array, default: () => [] }, editValue: { type: Array, default: () => [] } }, data() { return { value: [], cascaderKey:1 } }, watch: { editValue: { handler() { if (this.editValue) this.value = [...this.editValue] return }, immediate: true }, opyions: { handler() { this.cascaderKey ++ } } }, beforeDestroy() { this.value = [] }, methods: { /** * @description: 清空用户选择的当前的数据 并且清空当前高亮的项 */ clearV() { this.$refs.cascader.$refs.panel.clearCheckedNodes() }, /** * @description: 用户选择 组织 change 函数 * @return {object[] || object} */ handleChange() { this.$emit('cascaderHandler', () => { if (this.$refs.cascader.getCheckedNodes()[0] === undefined) { return { value: '', label: '' } } else { return this.$refs.cascader.getCheckedNodes()[0] } }) } } } </script> -
-
重置 activePath
-
ref拿到Cascader组件
this.$refs.cascaderRef.panel.activePath = [] this.$refs.cascaderRef.handleClear()
-
我这使用的方法是,名称 被清空 或者发生 改变时 通过 ref 调用子组件的 clearV 方法;
<template>
<sec-cascader
ref="cascader"
v-model="value"
class="cascader"
placeholder="请选择"
:options="options"
clearable
:show-all-levels="true"
filterable
:props="{ expandTrigger: 'click', multiple: false, checkStrictly: true }"
@change="handleChange"
></sec-cascader>
</template>
<script>
export default {
name: 'Cascader',
props: {
options: {
type: Array,
default: () => []
},
editValue: {
type: Array,
default: () => []
}
},
data() {
return {
value: [],
}
},
watch: {
editValue: {
handler() {
if (this.editValue) this.value = [...this.editValue]
return
},
immediate: true
}
},
beforeDestroy() {
this.value = []
},
methods: {
/**
* @description: 清空用户选择的当前的数据 并且清空当前高亮的项
* @return {*}
*/
clearV() {
// 清空当前高亮的项
this.$refs.cascader.panel.activePath = []
this.$refs.cascader.handleClear()
this.$refs.cascader.$refs.panel.clearCheckedNodes()
},
/**
* @description: 用户选择 组织 change 函数
* @return {object[]}
*/
handleChange() {
this.$emit('cascaderHandler', () => {
if (this.$refs.cascader.getCheckedNodes()[0] === undefined) {
return { value: '', label: '' }
} else {
return this.$refs.cascader.getCheckedNodes()[0]
}
})
}
}
}
</script>
父组件:
<script>
export default {
watch:{
"名称":{
async handler(newV) {
// 清空 组织 数据
await this.$nextTick(() => this.$refs['myCascader'].clearV())
if (newV !== '' || newV !== null){
// 请求 组织 数据
}
}
}
}
}
</script>
目前 用这种方式解决了;没有再报错;如果有类似错误的 小伙伴 也可以试试哦;也可参考以下 大佬的文章;
上述是我自己的理解;
源文章(更详细):记一次 element ui Cascader 级联选择器报错 - 掘金 (juejin.cn)
本文章只是做个关于 el-cascader 组件的报错记录;仅供参考;
🎉 以上 代码 或者 文档 有不对的地方,还请各位大佬指正;🧐
拜拜~