这篇文章主要为大家展示了“Element-ui中元素滚动时el-option超出元素区域的问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Element-ui中元素滚动时el-option超出元素区域的问题”这篇文章吧。
网站建设公司,为您提供网站建设,网站制作,网页设计及定制网站建设服务,专注于成都定制网站,高端网页制作,对成都混凝土搅拌罐车等多个行业拥有丰富的网站建设经验的网站建设公司。专业网站设计,网站优化推广哪家好,专业seo优化优化,H5建站,响应式网站。复现场景, 看图
分析原因
为简单起见, 把选项区域描述为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上动手脚了. 这里放一小段源码
0 && !loading"> {{ emptyText }}
全局搜索this.visible, 发现了这个方法
handleClose() { this.visible = false; },
这下好办了, 按图索骥, 顺藤摸瓜, 找到这个
后面的省略...找到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事件回调里判断是否有这个标记.
总结
依然存在的问题(隐患):
在mousewheel事件回调没有做节流, 考虑到有锁, 且滚轮事件触发的频率也不是很高(相对于mousemove事件来讲), 性能消耗并不大, 遂不做节流(主要是懒).
在mousewheel事件回调里,判断event.target 是否是在popperEl元素内部的方法感觉不是很靠谱, 且效率不高, 在mousedown 事件里判断是不是el-select元素的方法也存在同样的隐患, 后期再想办法修改(修改是不可能修改的, 又不是不能用).
在自定义模板用法里, 如果有嵌套的标签, 那么在mousewheel事件回调里判断event.target 是不是在popperEl元素内部的方法就崩溃了(这是个雷), 目前的解决办法是手动在嵌套的标签上都加上一个标记, 在事件里,添加这个标记的判断, 但是这种做法对于已经编写完成的模板无效, 只能再次修改, 考虑过使用递归向上查找, 但是效率不高, 性能消耗太大, 且自定义el-option模板这种情况在我们现阶段的业务中几乎不存在, 所以就没有考虑这个bug.
以上是“Element-ui中元素滚动时el-option超出元素区域的问题”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!
分享名称:Element-ui中元素滚动时el-option超出元素区域的问题-创新互联
网站URL:http://bzwzjz.com/article/dgiipe.html