前言
最近在开发一款使用了 element-ui 的低代码设计器,在开发的过程当中碰到了一些关于 element-ui 组件本身不合理的地方,并且在百度的基础上自己去阅读了一下 element-ui 的源码,也找出了这些问题的一个解决方案,下面就来看一下问题所在以及解决方法。
多选框的min设定为超过1就无法选中第一项
问题
组件本身存在一点问题,一旦min的值大于当前选中的选项超过2的时候,比方说,预选中的选项有一个,但是min的值设定为3,那么就会出现,我无论怎么点,都不会有反应。
这个问题在官方给出的在线运行例子中也是会出现的,感兴趣的可以去官网看一下:
element.eleme.io/#/zh-CN/com…
这个设计也不能说有问题,但是在实际的使用中就会有点奇怪,比方说一个3个的多选框,要求最少填写2个,那么你第1个永远都勾不上,并且这个问题好像在 vue3 版本的 elm 组件中已经得到解决。
原因
断点调试以及仔细阅读了选择之后的源码,会发现是一段代码在阻止这个选中状态
这段代码,仔细阅读就会发现,当我重新set整个的值的时候,这里会去计算 isLimitExceeded
这个值,当设置了 min 最小值,并且当前选中的选项的个数要小于min的话,就会导致 isLimitExceeded = true
并且在下面的 handleChange
这个函数中,一旦这个值为 true
就会直接返回
这样就导致了,万一我有四个多选框,最小要选择两个,但是我一进来的时候是 0 的预选值,那么无论我怎么点,都不会产生反应,因为每次一点下去触发 set
方法,isLimitExceeded
会被 判定为 true
,那么下面更改值的 handleChange
函数就一直不会触发,所以会导致这个问题。
解决方法
目前我使用的解决方法就是将源码中这个组件单独拷贝出来自己维护,比方说
而引用的这个组件的内容就是和官方的完全相同,因为组件都是全局注册的,所以就不会存在这个我们自己定义的组件会发生报错。
这样之后就可以解决这个问题了
级联选择删除过后不会清空选项
问题
还是一样参考官网的例子,想要自己尝试的可以一边看一边移步官网的源码
element.eleme.io/#/zh-CN/com…
clearable 这个能否清空的属性,会在选项后面新增一个移入后展示的 icon
但是点击之后就会发现,虽然输入框里面的值是被清空了,但是并不会删除选框内的内容
这里可以看到,清空了之后,选框还是展开的状态
原因
之前有使用过 vant
,在 vant
当中,级联选择并不是一个单独的组件,而是使用
它是由三个组件组合而成,一个输入框,用于回显,一个弹出层,用于承载选项,一个选项组件,用于给用户选择。
那么就能够大概感觉到,饿了么的清除功能,可能只是简单的清除了 input
内的内容。
那么接下来让我们移步源码,看看那个点击事件做了什么
从页面的元素展示以及代码,我们就能够看出来,饿了么的组件也是和 vant
一样的三段式,由 input
弹窗 弹窗内容 三个组成,那么我们接下去找到清空按钮的方法,通过元素选择找到删除按钮的 icon
名称,再去代码中查找
很容易就能够找到这个方法,再看一下方法的实现
清空了 input
绑定的 value
值,并且调用了 弹出内容层 的一个方法,这个 panel
就是利用 ref
找到了 弹出内容的对象,只不过加了一层,那么重点就在于调用的这个方法 clearCheckedNodes
从文件夹中找到 cascader-panel
这个组件所在。
看到我们想要的那个方法
这个方法的执行取决于我们传入给 级联组件 的配置,但是最后的本意都是要去清除掉选中的值, 也就是 chechedValue = []
可以看到清空之后这个值确实被清空了,也就是最后一项的选中的那个值,这也就是为什么没有初始化下拉框,因为它做的就只有这么多而已,想要初始化下拉框的话,还是得靠我们自己去查找。、
解决方法
我们想要的是整个选项都进行初始化,所以继续查找这个选项是什么参数控制的
根据高亮的类名,我们可以一路找到
cascader-panel
引用 cascader-menu
,cascader-menu
引用 cascader-node
最后在 cascader-node
当中
inActivePath
这个属性决定了是否加上 ‘in-active-path
’ 这个类,也就对应了是否高亮
那么去找这个属性的赋值,就能够发现
这个属性是根据 最外面的 cascader-panel
组件上的 activePath
这个属性。
那么就又回到了我们最外面的 cascader-panel
组件
我们可以在清空后的回调事件中,尝试着利用 $refs
清空 activePath
这个数组
this.$refs.myCascader.$refs.panel.activePath = []; // 清除高亮
然后我们就会发现,虽然高亮被清空了,但是还是处于展开状态,到这里就解决完一半
那么就还需要还原组件的展开状态
根据 cascader-panel
组件 和 浏览器中看到的元素,我们就能够比较直观的看出来,这个层级的展开取决于 menus
这个数组的个数,并且在搜索这个 menus
是如何生成的时候,能够发现
menus 将会这样被初始化,那么,我们的第一种解决方法也就出来了
handleChange(data){
if(data && data.length == 0) {
this.$refs.myCascader.$refs.panel.activePath = []; // 清除高亮
this.$refs.myCascader.$refs.panel.menus = [this.$refs.myCascader.$refs.panel.store.getNodes()]; // 初始化(只展示一级节点)
}
}
我们可以在 change
事件中去清空 activePath
的值,这样就会使得全部的联机下拉内容都消失,然后再去重新初始化一级节点。
或者直接调用 syncActivePath
这个方法,
这个方法在 activePath
和 checkedValue
都为空的时候,也会执行我们上面的那段逻辑,结局是一样的,并且在执行这个方法前,我们已经把 activePath
手动设为空了,checkedValue
也在前面说过,组件上层的点击方法会把它清空,也就是一定会走最下面的 else
逻辑
又或者直接执行 syncCheckedValue 这个函数,
这个函数会去判断当前选中的值和级联中的值是否相等,由于选中的值在点击事件中已经被清空了,所以一定是不相等的,就会重新初始化级联选择,也能够达到重置的目的。
那么到这里就解决了这个组件初始化的问题,具体要使用哪种方法,就看个人自己决定。
总结
本文简单的总结了一下最近开发中碰到的两个饿了么组件相关问题,可能算不上bug,设计之初可能就是这样,但是根据需求的需要,自己对其进行了一些调整以及研究为什么要这样调整,有更多的见解欢迎讨论
最后
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。
有需要的小伙伴,可以点击下方卡片领取,无偿分享