前言
最近在开发任务中碰到需要在新增和修改时使用动态加载级联选择器,但是当在修改时设置默认选中项,出现了后端数据返回较慢,导致无法选中和级联框选中了但input框不显示的问题,网上找到的方法也不是很有效,还得使用ref查看组件实例和element-ui cascader源码来寻找解决方法。
完整的实现代码在最后
1. 解决方法
我们知道使用动态加载的级联选择器需要使用lazyLoad函数,那就先开始寻找lazyLoad函数,使用ref查看组件实例,可以看到是在panel下。
再来看看源码,可以发现只需要传入Object数据即可,如:this.$refs.xxx.panel.lazyLoad(val)。
知道了传参和调用,但是传参的参数从哪来?如下图可以看到是从this.$refs.xxx.panel.menus[0]循环比对获取。
如果后端数据返回快的话可以达到要实现的选中效果,如果后端数据返回的较慢就会出现没选中的情况(可以自己在lazyLoad加个一秒延迟测试),这时就需要使用handleExpand(handleExpand也在panel下),并且要在请求结束后执行handleExpand,如何在请求结束时执行handleExpand,我们对代码进行如下修改:
先声明一个waitItemExecution函数并赋给menus[0]循环出的数据,最后在lazyLoad中执行waitItemExecution函数。效果如下图,是不是发现input框没有数据,这还是得去element-ui源码内寻找答案,接着往下看。
当级联选择器选择完毕时,watch下的checkedValue会触发,并执行computePresentContent接着computePresentContent再调用computePresentText。
是不是认为只要对checkedValue进行赋值,input框就有值了?可以试着去查看ref获取的实例下的checkedValue,你会发现已经有值在里面,那为什么没有触发呢?因为!isEqual(val, value)是判断不相等为true,而我们调用的方法不全,导致val和value相等,所以if里面的方法不执行,其实我们只需要调用computePresentText。waitItemExecution函数修改如下:
这样就实现了动态加载级联选择器默认选中的问题。以上的方法只解决了一层和二层的级联情况,超过二层的级联情况不适用,下面将给出最终解决方案代码。
2. 不同层级间的默认选中解决方法
对不同层级的默认选中只需要封装函数并互相调用就可实现(一到N层都可使用),以下是完整代码:
<template><div id="app"><el-cascader v-model="current" :props="props" ref="cascader"></el-cascader></div>
</template>
<script> let id = 0;
let list = [{value: '0',}, {value: '1',}, {value: '2',}, {value: '3',},
]
export default {name: 'App',data() {return {current: [],props: {lazy: true,lazyLoad(node, resolve) {const {level} = node;function f() {list = list.map((item, i) => ({label: level ? `${node.value}-${i}` : item.value,value: level ? `${node.value}-${i}` : item.value,leaf: item.value === '2' && level === 0 ? true : `${node.value}-${i}` === '3-2' ? true : level >= 2}))resolve(list)}if (level > 0) {setTimeout(() => {f()node.func && node.func(node)}, 1000)return}f()}}};},mounted() {this.current = ['1', '1-3', '1-3-0']// this.current = ['3', '3-2']// this.current = ['2']// this.current = ['0', '0-2', '0-2-3']for (let item of this.$refs.cascader.panel.menus[0]) {if (item.value === this.current[0]) {this.loadItem(item)return}}},methods: {handleItem(val) {if (val && val instanceof Object) {this.loadItem(val)}},loadItem(val) {val.func = this.waitItemExecutionthis.$refs.cascader.panel.lazyLoad(val)},waitItemExecution(val) {for (let item of val.children) {if (this.current[val.level] === item.value) {this.handleItem(item)break}}this.$refs.cascader.panel.handleExpand(val)this.$refs.cascader.computePresentText()},}
} </script>
最后
整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。
有需要的小伙伴,可以点击下方卡片领取,无偿分享