提问人:Jeje Pro 提问时间:10/22/2023 更新时间:10/22/2023 访问量:35
如果 DOM 发生变化,我找不到重新加载事件侦听器的好方法
I can't find a good method to reload event listener if the DOM changes
问:
我创建了一个 MouseContext,目标是在鼠标悬停时播放自定义动画。
如果可能的话,我希望只使用 useRef 来做到这一点,但我发现在我的应用程序的整个生命周期内必须将 ref 放在任何需要悬停操作的元素上是一种耻辱。
所以我尝试使用这样的手动事件侦听器:
useEffect(() => {
function inOutHandler(event) {
event.preventDefault();
const cursorType = event.type === "mouseenter" ? "active" : "";
if (
window.getComputedStyle(event.target)["cursor"].split(", ")[1] ===
"pointer"
)
mouseHandler({ type: "mouseHover", cursorType: cursorType });
window.removeEventListener("mouseenter", inOutHandler);
window.removeEventListener("mouseout", inOutHandler);
}
const links = document.querySelectorAll(
"a, .button, button"
);
for (let link of links) {
link.addEventListener("mouseenter", inOutHandler);
link.addEventListener("mouseout", inOutHandler);
}
}, []);
好吧,听起来不错,但是当一个新元素被添加到 DOM 中时,我必须再听一遍他的声音,处理起来很混乱。
再一次,我尝试了一些东西,用 MutationObserver :
const mutationObserver = new MutationObserver(async (mutationList, obs) => {
if (mutationList[0].addedNodes) {
function inOutHandler(event) {
event.preventDefault();
const cursorType = event.type === "mouseenter" ? "active" : "";
if (
window.getComputedStyle(event.target)["cursor"].split(", ")[1] ===
"pointer"
)
mouseHandler({ type: "mouseHover", cursorType: cursorType });
window.removeEventListener("mouseenter", inOutHandler);
window.removeEventListener("mouseout", inOutHandler);
}
const links = document.querySelectorAll(
"a, .admin .button, button"
);
for (let link of links) {
link.addEventListener("mouseenter", inOutHandler);
link.addEventListener("mouseout", inOutHandler);
}
}
});
useEffect(() => {
if (mainRef.current) {
mutationObserver.observe(mainRef.current, {
childList: true,
subtree: true,
});
return () => {
mutationObserver.disconnect();
};
}
}, [mutationObserver]);
这就是工作!但: 突变观察者也在监听从 dom 中消失的元素,因此,每次更改幻灯片(例如),我的监听器都会执行两次。这在性能方面给我带来了问题。
你们有什么建议给我吗?
答:
0赞
Jeje Pro
10/22/2023
#1
感谢 jfriend00 :
听起来您可能希望在侦听的地方使用事件传播 对于公共父级上的事件,而不是实际的 DOM 元素上的事件。 这样,您可以在父级上安装一次侦听器并自动安装 查看所有子事件,即使 DOM 元素来来去去(只要 您正在收听的父级不会更改)。
我不知道父监听器会处理 DOM 更改。 而且因为我检查当前元素 event.target 是否设置为指针,这仅适用于链接和按钮,谢谢!
在性能方面,这需要绝对测试应用程序的所有元素,我不知道这是否非常有影响力。
新代码:
function inOutHandler(event) {
const cursorType = event.type === "mouseenter" ? "active" : "";
if (
window.getComputedStyle(event.target)["cursor"].split(", ")[1] ===
"pointer"
)
mouseHandler({ type: "mouseHover", cursorType: cursorType });
mainRef.current.removeEventListener("mouseenter", inOutHandler);
mainRef.current.removeEventListener("mouseout", inOutHandler);
}
useEffect(() => {
if (!loader) {
mainRef.current.addEventListener("mouseenter", inOutHandler, true); // don't forget the true
mainRef.current.addEventListener("mouseout", inOutHandler, true);
}
}, [loader]);
评论