问题场景:有页面内嵌了表格(含滚动条),内嵌了大量input和select,在点击select出现下拉框时,正常的情况是图1,但是在滚动表格内的滚动条时,会出现图二的情况。
导致原因:select的下拉框的元素标签不是跟随在select之后,而是在body标签下面,并且z-index较高,如图3。
图1
图2
图3
解决办法
首先,尝试popper-append-to-body属性设置为false之后无效。
有效的解决办法来自https://www.e-learn.cn/topic/2821254,但是应用于公司的组件实现存在一定的问题。
该文章的核心思想是,
- 监听鼠标按下事件;
- 当鼠标按下时,判断点击元素是不是select,如果是置lock为false;如果不是直接返回;
- 当鼠标再次点击时,点击非select元素且lock为false,则强制执行鼠标按下、抬起事件(目的时让select下拉框收起),置lock为true;
- 监听滚轮事件;
- 当鼠标位置下方的元素是select,select内置滚动条,则直接返回;
- 当鼠标位置下方的元素非select,则强制执行鼠标按下、抬起事件(目的时让select下拉框收起),置lock为true;
1. 创建js文件
// 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 => {
const classList = e.target.classList;
// 该判断条件是用来判断点击的是否为下拉框
// el-select__caret代表是点击小三角出现下拉框,el-input__inner代表点击的整个input框
// 如果公司组件的类名不同,对应修改即可
if (
(classList && classList.contains('el-select__caret')) ||
(classList && classList.contains('el-input__inner'))
) {
lock = false;
return;
}
if (lock) return;
fakeClickOutSide();
};
const mousewheelHandle = e => {
// 如果当前select本身有滚动条,则直接返回
// 原文对于classList没有判空,会报错
if (
lock ||
(e.target.classList.length !== 0 &&
e.target.classList.contains('el-select-dropdown__item')) ||
(e.target.parentNode.classList !== undefined &&
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;
}
};
2. 使用
在想要引入的组件内
import fackClickOutSide from '@/mixin/fackClickOutSide.js';
export default {
name: 'FormWithAnchor',
mixins: [fackClickOutSide],
}
3.知识点
1. Event
Event()构造函数创建一个新的Event。
event = new Event(typeArg,eventInit);
typeArg:事件名称;
eventInit:这是一个对象,包含以下字段:
bubbles
:(可选)Boolean
指示事件是否冒泡。默认是false
。cancelable
:(可选)aBoolean
表示是否可以取消该事件。默认是false
。
2. document.dispatch
dispatchEvent()
就是触发执行,
dom.dispatchEvent(eventObject)
,参数eventObject
表示事件对象,是createEvent()
方法返回的创建的Event
对象。
作用:触发执行。例如:鼠标未按下,触发鼠标按下的event函数,能达到和鼠标按下一样的效果。
3. DOM addEventListener添加事件监听函数
element.addEventListener(event, function, useCapture)
event:必须。字符串,指定事件名。
function: 必须。指定要事件触发时执行的函数。
useCapture:可选。布尔值,指定事件是否在捕获或冒泡阶段执行。可能值:
- true:事件句柄在捕获阶段执行
- false-:默认。事件句柄在冒泡阶段执行
4. e.target
谁触发事件代表的就是谁。
target 属性规定哪个 DOM 元素触发了该事件; target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!