绕过捕获和冒泡向元素发送事件
Dispatch event to element bypassing capturing and bubbling
自 dispatchEvent
起,根据 docs,将应用:
normal event processing rules (including the capturing and optional
bubbling phase)
我正在寻找类似的东西,但有一种方法可以跳过这个过程并直接在元素上触发事件。在绕过处理阶段时触发默认元素事件行为。
例如,在 window
级别捕获事件(在它到达其他捕获触发器之前)并将其直接传递给直接调用它的组件(文本区域)。
(例如不通过层次结构触发文本区域的默认按键)
我一直在尝试这样做,但如果在 window 级别有另一个事件,这将不起作用:
window.addEventListener("keydown", this.keyDown, true);
keyDown = (event) => {
event.preventDefault();
event.nativeEvent && event.nativeEvent.stopImmediatePropagation();
event.stopImmediatePropagation && event.stopImmediatePropagation();
event.stopPropagation();
// Pass event straight to the element
return false;
};
我希望在绕过处理时触发默认元素事件行为
可能有更优雅的方法来做到这一点,但一个选择是先从 DOM 中删除元素,将事件分派给它,然后将其放回 DOM:
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
const input = document.querySelector('input');
input.addEventListener('keydown', () => {
console.log('input keydown');
});
const node = document.createTextNode('');
input.replaceWith(node);
input.dispatchEvent(new Event('keydown'));
node.replaceWith(input);
<input>
由于在分派事件时该元素不在 DOM 中,因此 曾 作为其祖先的元素将看不到该事件。
请注意,事件被分派到分离的元素 ,甚至没有被分派到事件被分派到的元素的父元素或子元素。
如果不事先完全从 DOM 中删除元素,如果输入可以存在于影子 DOM 中,您也可以在那里向它调度一个事件,并且该事件不会捕获向下或向上冒泡(虽然用户输入不是自定义事件,但会传播):
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
outer.attachShadow({mode: 'open'});
const input = document.createElement('input');
outer.shadowRoot.append(input);
input.addEventListener('keydown', () => {
console.log('input keydown');
});
input.dispatchEvent(new Event('keydown'));
<div id="outer"></div>
另一种方法是在 捕获 阶段调用 stopPropagation
和 stopImmediatePropagation
,在最开始,当事件处于 window
,然后手动调用你想要的监听函数。确保在页面 运行 上的任何其他脚本之前附加 您的 window 侦听器,以确保页面的 none 侦听器可以看到该事件第一:
// Your script:
const input = document.body.appendChild(document.createElement('input'));
input.className = 'custom-extension-element';
const handler = (e) => {
setTimeout(() => {
console.log(e.target.value);
});
};
window.addEventListener(
'keydown',
(e) => {
if (e.target.closest('.custom-extension-element')) {
e.stopImmediatePropagation(); // Stop other capturing listeners on window from seeing event
e.stopPropagation(); // Stop all other listeners
handler(e);
}
},
true // add listener in capturing phase
);
// Example page script
// which tries to attach listener to window in capturing phase:
window.addEventListener(
'keydown',
(e) => {
console.log('page sees keydown');
},
true
);
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
解决传播问题的最佳方法是只执行函数:
function tester(){
console.log("Just fire the function! Don't dispatchEvent!");
}
tester();
document.getElementById('test').onkeyup = function(e){
e.stopPropagation();
console.log(this.id); console.log(e.target); tester();
}
document.body.onkeyup = ()=>{
console.log("This shouldn't fire when on #test");
}
<input id='test' type='text' value='' />
自 dispatchEvent
起,根据 docs,将应用:
normal event processing rules (including the capturing and optional bubbling phase)
我正在寻找类似的东西,但有一种方法可以跳过这个过程并直接在元素上触发事件。在绕过处理阶段时触发默认元素事件行为。
例如,在 window
级别捕获事件(在它到达其他捕获触发器之前)并将其直接传递给直接调用它的组件(文本区域)。
(例如不通过层次结构触发文本区域的默认按键)
我一直在尝试这样做,但如果在 window 级别有另一个事件,这将不起作用:
window.addEventListener("keydown", this.keyDown, true);
keyDown = (event) => {
event.preventDefault();
event.nativeEvent && event.nativeEvent.stopImmediatePropagation();
event.stopImmediatePropagation && event.stopImmediatePropagation();
event.stopPropagation();
// Pass event straight to the element
return false;
};
我希望在绕过处理时触发默认元素事件行为
可能有更优雅的方法来做到这一点,但一个选择是先从 DOM 中删除元素,将事件分派给它,然后将其放回 DOM:
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
const input = document.querySelector('input');
input.addEventListener('keydown', () => {
console.log('input keydown');
});
const node = document.createTextNode('');
input.replaceWith(node);
input.dispatchEvent(new Event('keydown'));
node.replaceWith(input);
<input>
由于在分派事件时该元素不在 DOM 中,因此 曾 作为其祖先的元素将看不到该事件。
请注意,事件被分派到分离的元素
如果不事先完全从 DOM 中删除元素,如果输入可以存在于影子 DOM 中,您也可以在那里向它调度一个事件,并且该事件不会捕获向下或向上冒泡(虽然用户输入不是自定义事件,但会传播):
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
outer.attachShadow({mode: 'open'});
const input = document.createElement('input');
outer.shadowRoot.append(input);
input.addEventListener('keydown', () => {
console.log('input keydown');
});
input.dispatchEvent(new Event('keydown'));
<div id="outer"></div>
另一种方法是在 捕获 阶段调用 stopPropagation
和 stopImmediatePropagation
,在最开始,当事件处于 window
,然后手动调用你想要的监听函数。确保在页面 运行 上的任何其他脚本之前附加 您的 window 侦听器,以确保页面的 none 侦听器可以看到该事件第一:
// Your script:
const input = document.body.appendChild(document.createElement('input'));
input.className = 'custom-extension-element';
const handler = (e) => {
setTimeout(() => {
console.log(e.target.value);
});
};
window.addEventListener(
'keydown',
(e) => {
if (e.target.closest('.custom-extension-element')) {
e.stopImmediatePropagation(); // Stop other capturing listeners on window from seeing event
e.stopPropagation(); // Stop all other listeners
handler(e);
}
},
true // add listener in capturing phase
);
// Example page script
// which tries to attach listener to window in capturing phase:
window.addEventListener(
'keydown',
(e) => {
console.log('page sees keydown');
},
true
);
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
解决传播问题的最佳方法是只执行函数:
function tester(){
console.log("Just fire the function! Don't dispatchEvent!");
}
tester();
document.getElementById('test').onkeyup = function(e){
e.stopPropagation();
console.log(this.id); console.log(e.target); tester();
}
document.body.onkeyup = ()=>{
console.log("This shouldn't fire when on #test");
}
<input id='test' type='text' value='' />