element-ui 多选框和级联选择的部分bug以及解决方法


theme: channing-cyan

本文正在参加「金石计划 . 瓜分6万现金大奖」

前言

最近在开发一款使用了 element-ui 的低代码设计器,在开发的过程当中碰到了一些关于 element-ui 组件本身不合理的地方,并且在百度的基础上自己去阅读了一下 element-ui 的源码,也找出了这些问题的一个解决方案,下面就来看一下问题所在以及解决方法。

多选框的min设定为超过1就无法选中第一项

问题

组件本身存在一点问题,一旦min的值大于当前选中的选项超过2的时候,比方说,预选中的选项有一个,但是min的值设定为3,那么就会出现,我无论怎么点,都不会有反应。

这个问题在官方给出的在线运行例子中也是会出现的,感兴趣的可以去官网看一下:

https://element.eleme.io/#/zh-CN/component/checkbox

Pasted image 20221031133617.png

动画1.gif

这个设计也不能说有问题,但是在实际的使用中就会有点奇怪,比方说一个3个的多选框,要求最少填写2个,那么你第1个永远都勾不上,并且这个问题好像在 vue3 版本的 elm 组件中已经得到解决。

原因

断点调试以及仔细阅读了选择之后的源码,会发现是一段代码在阻止这个选中状态

image.png

这段代码,仔细阅读就会发现,当我重新set整个的值的时候,这里会去计算 isLimitExceeded 这个值,当设置了 min 最小值,并且当前选中的选项的个数要小于min的话,就会导致 isLimitExceeded = true 并且在下面的 handleChange 这个函数中,一旦这个值为 true 就会直接返回

image.png

这样就导致了,万一我有四个多选框,最小要选择两个,但是我一进来的时候是 0 的预选值,那么无论我怎么点,都不会产生反应,因为每次一点下去触发 set 方法,isLimitExceeded 会被 判定为 true ,那么下面更改值的 handleChange 函数就一直不会触发,所以会导致这个问题。

解决方法

目前我使用的解决方法就是将源码中这个组件单独拷贝出来自己维护,比方说

image.png

而引用的这个组件的内容就是和官方的完全相同,因为组件都是全局注册的,所以就不会存在这个我们自己定义的组件会发生报错。

image.png

这样之后就可以解决这个问题了

动画1.gif

级联选择删除过后不会清空选项

问题

还是一样参考官网的例子,想要自己尝试的可以一边看一边移步官网的源码

https://element.eleme.io/#/zh-CN/component/cascader

clearable 这个能否清空的属性,会在选项后面新增一个移入后展示的 icon

Pasted image 20221104171449.png

但是点击之后就会发现,虽然输入框里面的值是被清空了,但是并不会删除选框内的内容

Pasted image 20221104171540.png

这里可以看到,清空了之后,选框还是展开的状态

原因

之前有使用过 vant,在 vant 当中,级联选择并不是一个单独的组件,而是使用

Pasted image 20221104171722.png

它是由三个组件组合而成,一个输入框,用于回显,一个弹出层,用于承载选项,一个选项组件,用于给用户选择。

那么就能够大概感觉到,饿了么的清除功能,可能只是简单的清除了 input 内的内容。

那么接下来让我们移步源码,看看那个点击事件做了什么

Pasted image 20221104172210.png

Pasted image 20221104172128.png

从页面的元素展示以及代码,我们就能够看出来,饿了么的组件也是和 vant 一样的三段式,由 input 弹窗 弹窗内容 三个组成,那么我们接下去找到清空按钮的方法,通过元素选择找到删除按钮的 icon 名称,再去代码中查找

Pasted image 20221104172419.png

很容易就能够找到这个方法,再看一下方法的实现

Pasted image 20221104172446.png

清空了 input 绑定的 value 值,并且调用了 弹出内容层 的一个方法,这个 panel 就是利用 ref 找到了 弹出内容的对象,只不过加了一层,那么重点就在于调用的这个方法 clearCheckedNodes

Pasted image 20221104172531.png

从文件夹中找到 cascader-panel 这个组件所在。

Pasted image 20221104172708.png

看到我们想要的那个方法

Pasted image 20221104173336.png

这个方法的执行取决于我们传入给 级联组件 的配置,但是最后的本意都是要去清除掉选中的值,
也就是 chechedValue = []

Pasted image 20221104173714.png

可以看到清空之后这个值确实被清空了,也就是最后一项的选中的那个值,这也就是为什么没有初始化下拉框,因为它做的就只有这么多而已,想要初始化下拉框的话,还是得靠我们自己去查找。、

解决方法

我们想要的是整个选项都进行初始化,所以继续查找这个选项是什么参数控制的

根据高亮的类名,我们可以一路找到

Pasted image 20221104174840.png

cascader-panel 引用 cascader-menucascader-menu 引用 cascader-node 最后在 cascader-node 当中

Pasted image 20221104174936.png

inActivePath 这个属性决定了是否加上 ‘in-active-path‘ 这个类,也就对应了是否高亮

Pasted image 20221104175123.png

那么去找这个属性的赋值,就能够发现

Pasted image 20221104175156.png

Pasted image 20221104175207.png

这个属性是根据 最外面的 cascader-panel 组件上的 activePath 这个属性。

那么就又回到了我们最外面的 cascader-panel 组件

我们可以在清空后的回调事件中,尝试着利用 $refs 清空 activePath 这个数组

this.$refs.myCascader.$refs.panel.activePath = []; // 清除高亮

然后我们就会发现,虽然高亮被清空了,但是还是处于展开状态,到这里就解决完一半

Pasted image 20221104175634.png

那么就还需要还原组件的展开状态

Pasted image 20221104180041.png

image.png

根据 cascader-panel 组件 和 浏览器中看到的元素,我们就能够比较直观的看出来,这个层级的展开取决于 menus 这个数组的个数,并且在搜索这个 menus 是如何生成的时候,能够发现

Pasted image 20221107092226.png

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 这个方法,

Pasted image 20221107092733.png

这个方法在 activePathcheckedValue 都为空的时候,也会执行我们上面的那段逻辑,结局是一样的,并且在执行这个方法前,我们已经把 activePath 手动设为空了,checkedValue 也在前面说过,组件上层的点击方法会把它清空,也就是一定会走最下面的 else 逻辑

又或者直接执行 syncCheckedValue 这个函数,

Pasted image 20221107093331.png

这个函数会去判断当前选中的值和级联中的值是否相等,由于选中的值在点击事件中已经被清空了,所以一定是不相等的,就会重新初始化级联选择,也能够达到重置的目的。

那么到这里就解决了这个组件初始化的问题,具体要使用哪种方法,就看个人自己决定。

总结

本文简单的总结了一下最近开发中碰到的两个饿了么组件相关问题,可能算不上bug,设计之初可能就是这样,但是根据需求的需要,自己对其进行了一些调整以及研究为什么要这样调整,有更多的见解欢迎讨论

参考

el-cascader 级联选择器清空初始化

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容