【发布时间】:2012-04-11 22:38:18
【问题描述】:
tl;博士总结
编写一个函数,当注册以处理层次结构中多个元素上的特定事件时,该函数在冒泡期间到达的第一个元素上执行,但在进一步向上冒泡时不执行(或提前返回)。 (实际上并未停止事件的传播。)
简单示例
给定this HTML…
<!DOCTYPE html>
<body>
<div><button>click</button></div>
<script>
var d = document.querySelector('div'),
b = document.querySelector('button');
d.addEventListener('mousedown',clickPick,false);
d.addEventListener('mousedown',startDrag,false);
b.addEventListener('mousedown',startDrag,false);
function clickPick(){ console.log('click',this.tagName); }
function startDrag(){ console.log('drag',this.tagName); }
</script>
...单击按钮会产生以下输出:
拖动按钮
点击 DIV
拖动DIV
但是,我不想拖动 div。具体来说,我希望startDrag 只在<button> 上被处理一次,这是它在特定传播链中注册的最叶子元素。
“工作”解决方案
以下 JavaScript 代码 has been tested 可在 IE9、Chrome18、FF11、Safari5 和 Opera11 上工作。
function startDrag(evt){
if (seenHandler(evt,startDrag)) return;
console.log('drag',this.tagName);
}
function seenHandler(evt,f){
if (!evt.handlers) evt.handlers=[];
for (var i=evt.handlers.length;i--;) if (evt.handlers[i]==f) return true;
evt.handlers.push(f);
return false;
}
即使您使用全局 window.event 对象,上述内容不也适用于 IE8;冒泡期间不会重复使用相同的event 对象。
问题
但是,我不确定上述方法是否保证可以工作......也不确定它是否尽可能优雅。
- 相同的
event对象是否保证在传播过程中向上传递? -
event对象是否保证不会被重复用于不同的事件调度? -
event对象是否保证支持向其添加 expando 属性? - 您能想出一种更优雅的方法来检测当前调度事件时是否已经看到相同的事件处理函数?
现实世界的应用
想象一下这个 SVG 层次结构……
<g>
<rect … />
<rect … />
<circle … />
</g>
...和a user who wants 能够通过拖动其中的任何矩形来拖动整个组,并且还能够通过拖动来仅拖动圆圈。
现在混入一个generic dragging library,它会为您处理大部分细节。我提议修改这个库,这样如果用户向<g> 和<circle> 添加一个拖动处理程序,那么在圆圈上拖动会自动阻止拖动在组上启动,但不会停止所有@ 的传播987654337@ 事件(因为用户可能有一个高级处理程序用于其他需要的目的)。
【问题讨论】:
标签: javascript html events javascript-events