Столкнулся с проблемой в своём календарике - есть два элемента, один из которых позиционируется абсолютно на весь экран, полупрозрачная затемняющая занавеска а второй - форма. Вы наверняка видели такие решения при показе картинок в lightbox или аутидентификации на habrahabr'е..
<div id='form_bg' onclick="$('form_bg').hide();$('form').hide();">
<div id='form'></div>
</div>
Проблема в том, что при любом нажатии на внутренний элемент, событие автоматом вызывается на родительском элементе. Это заставило меня задуматься как над решением, так и над теорией как браузеры работают.
Две с половиной модели
Как оказывается, существует две модели передачи событий в объектно-ориентированной иерархии
- Пузырьковый метод (bubbling), когда событие возникает внутри и затем передаётся родительским элементам наружу. MS Internet Explorer, Opera, Firefox
- Захват события (capturing), событие обрабатывается сначала у родителей, а потом проникает глубже. Opera, Firefox
Консорциум W3C благоразумно решили что разработчикам может быть удобно в любую сторону направлять события (event propagation), поэтому по стандарту две модели объединены - событие сначала захватывается, а потом возвращается как пузырёк.
Таким образом разработчик может привязать вызываемый метод к фазе события:
$('form_bg').addEventListener('click',hideBackground,true);
// true - говорит о фазе capturing $('form').addEventListener('click',doNothing,false);
// false - говорит о фазе bubbling
Получается что при клике на form_bg происходит сразу hideBackground, form на фазе capturing не вызывается, затем возвращаясь, в фазе bubbling вызывается doNothing.
Традиции по умолчанию
Модель W3C приятна, но по умолчанию по всей видимости из-за IE, обычная регистрация события подразумевает bubbling фазу, т.е. изнутри наружу. А это в свою очередь значит, что если я явно укажу на родительский элемент:
$('form_bg').onclick = hideBackground; // или как выше - в <div id='form_bg' onclick=..
То любое событие без остановки вызывает у всех родительских элементов обработку onclick-события. Есть у них оно или нет, вплоть до корня - document.
Заплыв без пузырьков
В кросс-браузерном варианте для остановки распространения обработки события к родительским элементам, надо поменять параметр cancelBubble на true (для IE) и вызывать функцию stopPropagation (W3C модель):
function hideBackground(e){
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}
Теперь мне интересно как устроена модель обработки событий в других языках и платформах - Java, NET, Flash..
Написано по мотивам статьи "Event order".

Комментарии
в IE7 не отображается пример после фразы "метод к фазе события"
и еще один баг в IE:
кликаю на ответить - выдает script error
firebug тоже ругается, но форму для ответа открывает
Например, реализация «preventDefault»:
Function.prototype.preventDefault = function() {
var ev = this.arguments[0] || window.event;
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
};
тепер в любой функции, чтобы предотвратить стандартное действие, нужно написать такую строчку:
arguments.callee.preventDefault();
C «topPropagation» аналогично.