【发布时间】:2019-12-18 18:21:17
【问题描述】:
我创建了一个自定义 Slider 组件,除了一个问题外,它可以完美运行。
如果它存在于模式中,则它的 mouseUp 事件会在其下方的所有事件(z-index-wise)之前在元素本身上触发。
这是因为要拥有一个漂亮的滑块,您需要将 mouseMove 和 mouseUp 事件附加到文档而不是滑块本身,这样即使鼠标移动,您仍然可以移动拇指并捕获鼠标向上事件滑动拇指时离开滑块。
因此,我现在遇到了mouseUp 事件导致其下方元素的点击事件在滑块元素之前运行的问题。这会导致下面的按钮点击和模式关闭等问题(因为这些都是点击事件)。
一个潜在的解决方案是对所有可能被拦截的潜在事件处理程序添加检查(类似于if (thisModalOpened) { return false; } 对所有其他各种元素),但该解决方案似乎有点混乱。
有没有更好的方法?一种反转冒泡顺序的方法似乎可行,因为这样我就可以在 mouseUp 中为 Slider 组件调用 stopPropagation。但是,我不确定是否可以这样做,因为当前事件侦听器已在文档中注册,以便可以在元素本身之外检测到它。
一些代码sn-ps:
componentDidMount() {
document.addEventListener("pointermove", this.onThumbMove, false);
document.addEventListener("pointerup", this.onThumbUp, false);
}
onThumbDown = e => {
this.setState({ dragging: true, startX: this.getX(e) });
}
onThumbMove = e => {
if (this.state.dragging) {
this.setState({ position: e.clientX });
}
}
onThumbUp = e => {
if (this.state.dragging) {
let value = this.getValue();
this.setState({ dragging: false }, () =>
this.props.onSubmit(value);
});
}
}
<div onPointerDown={this.onThumbDown} ref={this.sliderRef}>
<div>+</div>
</div>
编辑: 好的,我想我终于找到了问题所在(但我还不知道解决方案):所以,模态框通常(我的也是如此)有黑色背景您可以单击以轻松关闭模式。我可以将黑色背景作为模型内容的直接父级或父级的兄弟。
如果我将它作为直接父级,那么我必须在每个可能的子组件上调用stopPropagation / return false,以便单击它们不会导致单击向上传播并单击背景模态并使其关闭。所以我不希望它成为父母,因为那太麻烦了。
另一方面,如果我将它作为父级的兄弟,那么我不能在文档thumbUp 事件上调用stopPropagation,因为模态背景蒙版不是直接父级,因此它将被注册为尽管有stopPropagation 调用,但仍单击并关闭模式,因为它不是直接父级。
基本上,这两种方法都行不通。我不知道如何调和。
【问题讨论】:
-
是的,你可以。请发布您当前的事件监听器和其他相关代码 sn-ps。
-
当然可以。秒。
-
您可以通过将
true作为第三个参数传递给event listner来反转事件冒泡阶段,例如elem.addEventListener("mouseup", function () { console.log("mouseup event"); }, true); -
@SarveshMahajan 我试过了,但似乎没有用。它已注册文档,因此将其设置为
true只需先将其发送到文档(这已经在发生)。理想情况下,我可以将它注册到文档中,但让它从 Slider 组件开始。 -
如果按钮是滑块的父级,而不是捕获,则默认冒泡正是您想要的。这里还有其他事情发生,特别是如果您在移动设备上进行测试。一起调用 stopPropagation 和 stopImmediatePropagation 以确保没有模拟事件被触发。而且由于 mouseup 和所有其他模拟事件都是在触摸事件之后触发的,因此您还需要在 touchmove 和 touchend 中调用它。
标签: javascript html reactjs modal-dialog event-bubbling