Element-ui中 元素滚动时el-option超出元素区域的问题

栏目: CSS · 发布时间: 4年前

内容简介:为简单起见, 把选项区域描述为popperEl我最初想到的解决方案是通过css解决,通过popper-class属性给Select下拉框添加类名,然后用css来做, 试了一下这个方案并不可行(只能在某些特定的场景下起作用),遂放弃,可能最优雅最高性能的方法就是用css来搞定, 有踩过这个坑的朋友请指点一下通过监听$root的scroll事件,利用事件冒泡,只需要在根元素上添加scroll事件的监听就可以了, 测试一番之后, 发现scroll事件根本不支持冒泡, event.bubbles为false)。
Element-ui中 元素滚动时el-option超出元素区域的问题

分析原因

为简单起见, 把选项区域描述为popperEl

  • popperEl的z-index 比较大, 会覆盖在其他元素上面
  • popperEl默认是插入body元素的(可以将popper-append-to-body设为false后不插入到body)
  • popperEl是在mouseup事件里去做隐藏逻辑的, 而按下鼠标, 移动滚动条的时候, 并没有触发mouseup事件.
  • popperEl并没有监听滚动事件(没法监听, 也没必要监听)

解决方案

方案一

我最初想到的解决方案是通过css解决,通过popper-class属性给Select下拉框添加类名,然后用css来做, 试了一下这个方案并不可行(只能在某些特定的场景下起作用),遂放弃,可能最优雅最高性能的方法就是用css来搞定, 有踩过这个坑的朋友请指点一下

方案二

通过监听$root的scroll事件,利用事件冒泡,只需要在根元素上添加scroll事件的监听就可以了, 测试一番之后, 发现scroll事件根本不支持冒泡, event.bubbles为false)。

方案三

通过查看element-ui 的select.vue, 发现控制popperEl显隐的是visible 和 emptyText这两个实例属性, 很明显, emptytext是不能动的, 只能在visible上动手脚了. 这里放一小段源码

<transition
  name="el-zoom-in-top"
  @before-enter="handleMenuEnter"
  @after-leave="doDestroy">
  <el-select-menu
    ref="popper"
    :append-to-body="popperAppendToBody"
    v-show="visible && emptyText !== false">
    <el-scrollbar
      tag="ul"
      wrap-class="el-select-dropdown__wrap"
      view-class="el-select-dropdown__list"
      ref="scrollbar"
      :class="{ 'is-empty': !allowCreate && query && filteredOptionsCount === 0 }"
      v-show="options.length > 0 && !loading">
      <el-option
        :value="query"
        created
        v-if="showNewOption">
      </el-option>
      <slot></slot>
    </el-scrollbar>
    <p
      class="el-select-dropdown__empty"
      v-if="emptyText &&
        (!allowCreate || loading || (allowCreate && options.length === 0 ))">
      {{ emptyText }}
    </p>
  </el-select-menu>
</transition>
复制代码

全局搜索this.visible, 发现了这个方法

handleClose() {
    this.visible = false;
},
复制代码

这下好办了, 按图索骥, 顺藤摸瓜, 找到这个

<template>
  <div
    class="el-select"
    :class="[selectSize ? 'el-select--' + selectSize : '']"
    @click.stop="toggleMenu"
    v-clickoutside="handleClose">
    后面的省略...
复制代码

找到v-clickoutside指令之后, 豁然开朗 原来点击其他区域的时候, popperEl会自动关闭的奥秘在这里, 结合方案二的灵感, 现给出如下代码.

// src/mixins/fackClickOutSide.js
let lock = true;
let el = null;
const MousedownEvent = new Event('mousedown', {bubbles:true});
const MouseupEvent = new Event('mouseup', {bubbles:true});
const fakeClickOutSide = () => {
  document.dispatchEvent(MousedownEvent);
  document.dispatchEvent(MouseupEvent);
  lock = true; // console.log('dispatchEvent');
};
const mousedownHandle = e => {
  let classList = e.target.classList;
  if(classList.contains('el-select__caret') || classList.contains('el-input__inner')) {
    lock = false;
    return;
  }
  if(lock) return;
  fakeClickOutSide();
};
const mousewheelHandle = e => {
  if(lock || e.target.classList.contains('el-select-dropdown__item') || e.target.parentNode.classList.contains('el-select-dropdown__item')) return;
  fakeClickOutSide();
};
const eventListener = (type) => {
  el[type + 'EventListener']('mousedown', mousedownHandle);
  window[type + 'EventListener']('mousewheel', mousewheelHandle);
  window[type + 'EventListener']('DOMMouseScroll', mousewheelHandle); // fireFox 3.5+ 
}
export default {
  mounted() {
    el = this.$root.$el;
    el.addFakeClickOutSideEventCount = el.addFakeClickOutSideEventCount || 0;
    (! el.addFakeClickOutSideEventCount) && this.$nextTick(() => {
      eventListener('add');
    });
    el.addFakeClickOutSideEventCount += 1;
  },
  destroyed() {
    eventListener('remove');
    el.addFakeClickOutSideEventCount -= 1;
  },
}
复制代码

使用姿势

建议在根组件上混合进去, 当然,你也可以在需要的组件上去混合(不太建议, 这点代码性能损耗应该不大吧, 哈哈哈)

// src/App.vue
import fakeClickOutSide from '@/mixins/fakeClickOutSide.js'
export default {
    name: 'App',
    mixins: [fakeClickOutSide],
}
复制代码

测试

常规基础用法 和 自定义模板用法(模板内没有嵌套的标签) 均完美通过.

自定义模板内如果嵌套多级标签, 需要在标签上添加标记,然后在mousewheel事件回调里判断是否有这个标记.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JAVASCRIPT语言精髓与编程实践

JAVASCRIPT语言精髓与编程实践

周爱民 / 电子工业出版社 / 2008-3 / 68.00元

《JAVASCRIPT语言精髓与编程实践》讲述了JavaScript的语言实现与扩展,主要包括以下三个方面的内容:(1)动态、函数式语言,以及其它语言特性在JavaScript的表现与应用;(2)如何用动态函数式语言的特性来扩展JavaScript的语言特性与框架;(3)如何将JavaScript引擎整合到其它高级语言的开发过程中。一起来看看 《JAVASCRIPT语言精髓与编程实践》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具