通过重叠的网格项使指针事件冒泡
Make pointer events bubble through overlapping grid items
在我的应用程序中,我有两个重叠的网格项。因此,点击或悬停等指针事件仅在上层元素上触发(根据 z-index 或出现顺序)。
我想知道是否有办法(react/js 或 css 明智地)让两个项目都检测到指针事件或至少模拟该行为:
这是我的例子:
export default function App() {
function onClick() {
console.log("click");
}
return (
<div className="grid">
<div className="item-1" />
<div className="item-2" onClick={onClick}>
Click
</div>
</div>
);
}
.grid {
display: grid;
grid-template-columns: 100px 100px 100px;
}
.item-1 {
grid-row: 1;
grid-column: 1/-1;
background-color: deeppink;
}
.item-1:hover {
background-color: lime;
}
.item-2 {
grid-row: 1;
grid-column: 2;
border: 1px solid black;
cursor: pointer;
}
function App() {
function onClick() {
console.log("click");
}
return (
<div className="grid">
<div className="item-1" />
<div className="item-2" onClick={onClick}>
Click
</div>
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
.grid {
display: grid;
grid-template-columns: 100px 100px 100px;
}
.item-1 {
grid-row: 1;
grid-column: 1/-1;
background-color: deeppink;
}
.item-1:hover {
background-color: lime;
}
.item-2 {
grid-row: 1;
grid-column: 2;
border: 1px solid black;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
看到这个codesandbox。
item-1
在悬停时改变颜色,item-2
在点击时触发一个函数。显然,当悬停在 item-2
上时,它会捕获悬停事件并且 item-1
不会改变它的颜色。
我正在寻找的是一种将悬停(并单击)item-2
也重定向到 item-1
或以某种方式“冒泡”通过这两个元素的方法。
我不想做的是改变html-结构,即两个元素必须是网格容器的平行子代。
点击:
有一种方法可以模拟这个。最好看在这个code sandbox,不过原理很简单
在上层元素上注册一个点击事件处理器。在处理程序中,执行您需要执行的任何操作,并决定是否要将点击传递到下方元素。如果是,则将pointer-events: none
应用于上层元素并调用document.elementFromPoint(event.pageX, event.pageY).click()
。这将在原始点击的位置搜索元素,并且由于上部元素不在路上,将 return 下部元素或该位置下部元素内的任何内容,然后模拟点击。然后只需应用 pointer-events: initial
即可恢复所有内容。
由于 DOM 元素自然冒泡,您可以在“上层结构”的顶部附加上层事件处理程序并取消内部事件处理程序。据我所知,它保留了正常的事件语义。
document.getElementById("upper").addEventListener("click", (event) => {
document.getElementById("upper").style.pointerEvents = "none";
document.elementFromPoint(event.pageX, event.pageY).click();
document.getElementById("upper").style.pointerEvents = "initial";
});
唯一需要注意的是,下层元素只会接收假点击事件,因此修改键和位置等属性将不可用。如果需要的话,最好单独传这个数据。
悬停:
编辑:我考虑过悬停部分并想出了这个解决方案:
将 mousemove
和 mouseout
处理程序添加到上部元素并检查 mousemove
是否 pageX
/ pageY
坐标在边界内使用 getBoundingClientRect
的其他元素的框。如果是,请将 class 添加到其他元素以指示它们正在悬停。然后在有 :hover
选择器的地方添加匹配的悬停 class 选择器。清除 mouseout
上的悬停 classes(并卸载等)。
我modified your sandbox显示悬停方法。
不过,此方法也有一个警告。如果您在上一个元素之上创建一个新元素,则不会调用 mouseout
。所以记住这一点。
在我的应用程序中,我有两个重叠的网格项。因此,点击或悬停等指针事件仅在上层元素上触发(根据 z-index 或出现顺序)。
我想知道是否有办法(react/js 或 css 明智地)让两个项目都检测到指针事件或至少模拟该行为:
这是我的例子:
export default function App() {
function onClick() {
console.log("click");
}
return (
<div className="grid">
<div className="item-1" />
<div className="item-2" onClick={onClick}>
Click
</div>
</div>
);
}
.grid {
display: grid;
grid-template-columns: 100px 100px 100px;
}
.item-1 {
grid-row: 1;
grid-column: 1/-1;
background-color: deeppink;
}
.item-1:hover {
background-color: lime;
}
.item-2 {
grid-row: 1;
grid-column: 2;
border: 1px solid black;
cursor: pointer;
}
function App() {
function onClick() {
console.log("click");
}
return (
<div className="grid">
<div className="item-1" />
<div className="item-2" onClick={onClick}>
Click
</div>
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
.grid {
display: grid;
grid-template-columns: 100px 100px 100px;
}
.item-1 {
grid-row: 1;
grid-column: 1/-1;
background-color: deeppink;
}
.item-1:hover {
background-color: lime;
}
.item-2 {
grid-row: 1;
grid-column: 2;
border: 1px solid black;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
看到这个codesandbox。
item-1
在悬停时改变颜色,item-2
在点击时触发一个函数。显然,当悬停在 item-2
上时,它会捕获悬停事件并且 item-1
不会改变它的颜色。
我正在寻找的是一种将悬停(并单击)item-2
也重定向到 item-1
或以某种方式“冒泡”通过这两个元素的方法。
我不想做的是改变html-结构,即两个元素必须是网格容器的平行子代。
点击:
有一种方法可以模拟这个。最好看在这个code sandbox,不过原理很简单
在上层元素上注册一个点击事件处理器。在处理程序中,执行您需要执行的任何操作,并决定是否要将点击传递到下方元素。如果是,则将pointer-events: none
应用于上层元素并调用document.elementFromPoint(event.pageX, event.pageY).click()
。这将在原始点击的位置搜索元素,并且由于上部元素不在路上,将 return 下部元素或该位置下部元素内的任何内容,然后模拟点击。然后只需应用 pointer-events: initial
即可恢复所有内容。
由于 DOM 元素自然冒泡,您可以在“上层结构”的顶部附加上层事件处理程序并取消内部事件处理程序。据我所知,它保留了正常的事件语义。
document.getElementById("upper").addEventListener("click", (event) => {
document.getElementById("upper").style.pointerEvents = "none";
document.elementFromPoint(event.pageX, event.pageY).click();
document.getElementById("upper").style.pointerEvents = "initial";
});
唯一需要注意的是,下层元素只会接收假点击事件,因此修改键和位置等属性将不可用。如果需要的话,最好单独传这个数据。
悬停:
编辑:我考虑过悬停部分并想出了这个解决方案:
将 mousemove
和 mouseout
处理程序添加到上部元素并检查 mousemove
是否 pageX
/ pageY
坐标在边界内使用 getBoundingClientRect
的其他元素的框。如果是,请将 class 添加到其他元素以指示它们正在悬停。然后在有 :hover
选择器的地方添加匹配的悬停 class 选择器。清除 mouseout
上的悬停 classes(并卸载等)。
我modified your sandbox显示悬停方法。
不过,此方法也有一个警告。如果您在上一个元素之上创建一个新元素,则不会调用 mouseout
。所以记住这一点。