无星的前端之旅(二十)-element-plus给el-sele

2021-04-28  本文已影响0人  无星灬

背景

element-plus中,el-select中可选项达到了500条,页面跳转销毁时导致异常卡顿(vue3.0.0版本,3.0.11版本有很大改善,建议升级)

因此需要进行分页操作。初步设想时当select中的options滚动到最底部的时候,触发加载更多,获取更多的可选项。

实现方式

打算通过指令实现,这样添加就很方便,预期一个指令

v-loadmore="loadMore"
1.png

搜一下

正常情况下,我们碰到的100个需求,99个都已经有人实现过了,所以我们就只需要搜一哈,就能找到答案。

果不其然,答案异常的多,只不过都是element-ui的,不过改动不多,应该问题不大,让我们来试一试。

开始踩坑

1.附上随处可搜的代码

我就不贴从哪抄的了,因为随处可以搜到

Vue.directive('loadMore', {
  bind(el, binding) {
    // 获取element-ui定义好的scroll盒子
    const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
    SELECTWRAP_DOM.addEventListener('scroll', function () {

      const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
      if (CONDITION) {
        binding.value()
      }
    })
  }
})

这个代码分析起来很简单

1.通过指令绑定的时候传递dom节点

2.再通过class选择器找到scroll的盒子节点

3.添加滚动监听事件

4.滚动到底,触发绑定事件

在element-ui上完美运行

但是

在element-plus不行,会提示找不到SELECTWRAP_DOM

因为SELECTWRAP_DOM为null,所以添加监听器就报错了

2.png

探寻不同

1.对比element-ui和element-plus的dom节点

3.png

左边是element-ui,右边是element-plus

节点都在,而且都在body下,按道理应该没问题

2.打印挂载的el节点

4.png

代码:element-ui

5.png

代码:element-plus

发现了没,plus下打印的节点,异常清爽,并且还有两行贴心的注释

<!--teleport start-->
<!--teleport end-->

3.vue3新增了Teleport

Teleport

在vue3刚出来的时候,我读过一遍文档,依稀记得添加了一个神奇的控件Teleport,可以把逻辑和展示分开,但是是它的逻辑在一块。

想必element-plus就是使用这种方式重构了select组件。

4.阅读源码

让我们翻开element-plus/packages/select/src/select.vue

6.png

映入眼帘的就是el-popper

我们再看看element-plus/packages/popper/src/index.vue

7.png

看来我们找到它了

5.定位联系

我们点击select,唤起对应的待选列表

如果一个页面有多个select,也是正常能唤起的

所以每个select与每个popper之间,应该存在着某种联系

继续阅读el-popper,果然,我们发现了一个值popperId

8.png

并且被赋值给了ariaDescribedby

回过头来看dom🌲

我们果然在select的标签上,找到了ariaDescribedby属性

9.png

并且再其对应的popper上,找到了这个id

10.png

那么问题解决了,我们只需要对指令稍作修改

最终指令

const loadMore = {
  mounted(el, binding) {
    const child = el.querySelector('.select-trigger');
    const id = child.getAttribute('ariadescribedby');
    const poper = document.getElementById(id);
    const SELECTDOWN_DOM = poper.querySelector('.el-scrollbar .el-select-dropdown__wrap');
    // 这里不能使用箭头函数!
    // eslint-disable-next-line func-names
    SELECTDOWN_DOM.addEventListener('scroll', function () {
      /**
       * scrollHeight 获取元素内容高度(只读)
       * scrollTop 获取或者设置元素的偏移值,
       *  常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
       * clientHeight 读取元素的可见高度(只读)
       * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
       * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
       */
      const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight;
      if (CONDITION) {
        binding.value();
      }
    });
  },
};

export default loadMore;

over

上一篇下一篇

猜你喜欢

热点阅读