美文网首页
无星的前端之旅(二十)-element-plus给el-sele

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

作者: 无星灬 | 来源:发表于2021-04-28 16:53 被阅读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

    相关文章

      网友评论

          本文标题:无星的前端之旅(二十)-element-plus给el-sele

          本文链接:https://www.haomeiwen.com/subject/ytnvrltx.html