Перехват события на этапе bubbling

 
0
 
JavaScript
ava
kaa | 06.08.2007, 11:42
В общем заготовка выпадающего меню и нужно чтобы при возникновении события mouseover не над пунктом меню все открытые пункты скрывались. Казалось бы что может быть проще?


//присваеваем обработчик события каждому пункту меню
$('*[@foo="my_drop_menu_item"]').mouseover(MenuOver);
//Устанавливаем bubble-слушатель события mouseover
$("body").mouseover(BubblingMouseOver);


function MenuOver(evt)
{
if(window.event)
{
var thisEvent = event;
}
else
{
var thisEvent = evt;
}
//Выполняем все необходимые действия с меню

//Останаваливаем всплывание(не останаваливается!)
thisEvent.stopPropagation();
}


function BubblingMouseOver(evt)
{
if(window.event)
{
var thisEvent = event;
}
else
{
var thisEvent = evt;
}

//Определяем фазу

if(thisEvent.eventPhase!=3)
{
return;
}
else
{
//код скрывающий меню
}
}



Тоесть если событие не всплывает то меню скрывать и ненадо

Беда вся в том что если я убираю комментарий с кода скрывающего меню - оно у меня скрывается ВСЕГДА! Даже если вызывается обработчик пункта меню. Я всю голову уже сломал.

Кто-нить ткните пожалста носом в ошибку smile
Comments (4)
ava
dXdYdZ | 07.08.2007, 02:20 #
Вам надо сделать следующее:
1) При наведении мыши показать меню и прикрепить обработчиком щелчка мыши к document.body функцию скрытия меню.
2) При выборе пункта меню оно должно пропасть, значит надо запустить функцию скрытия меню.
3) В функции скрытия меню надо отсоединить обработчик события click от document.body.

Я сам так недавно делал, и у меня всё работает нормально.
ava
smartov | 07.08.2007, 13:55 #
kaa,
Цитата (kaa @ 6.8.2007, 09:42 findReferencedText)
события mouseover не над пунктом меню

Событие onmouseover не над пунктом меню == событие onmouseout пункта меню.
Алгоритм получается следующий
для всех пунктов меню
onmouseover - показывает субменю этого пункта
onmouseout - скрывает субменю _всех_ пунктов
ava
kaa | 07.08.2007, 14:00 #
Спасибо, буду переваривать и пытаться

added later:
smartov,
я так тоже думал, но тут вот каакя загвоздка:
onmouseout и onmouseover будут веть обрабатываться в каждом пункте отдельно. Тоесть если я убираю курсор с дочернего пункта и перевожу его на родительский у меня эти два события наступят отдельно и последовательно, тогда по вашему алгоритму получится что:


onmouseout - скрывает субменю _всех_ пунктов
onmouseover - показывает субменю этого пункта - а вот тут уже ничего не сработает потомучто все пункты будут скрыты


Забыл сказать то делаю не просто выпадающее меню, менб с заранее неизвестным уровнем вложенности. Может конечно сильно замахнулся.


dXdYdZ,
А где уверенность что этот обработчик не будет вызываться пока у меня работает само меню? У меня ж вот в чем и была проблема: обработчик события того что курсор уже не над меню вызывался как-то через ж... (извините конечно smile )

Тоесть я в принципе отслеживал ситуацию где у меня курсор( над чем) сейчас вертится, но следующий код всё портил. Самое интересное что он вызывался даже при указании в обработчике меню остановить всплывание :(


function BubblingMouseOver(evt)
{
if(window.event)
{
var thisEvent = event;
}
else
{
var thisEvent = evt;
}

//Определяем фазу

if(thisEvent.eventPhase!=3)
{
return;
}
else
{
//код скрывающий меню
}
}
ava
dXdYdZ | 07.08.2007, 23:40 #
Вот пример меню из моей библиотеки. Работает нормально.

gmenu=function(node,params,templ)
{
this.template="<span bind='punkt' class='gmenuPunkt'>&nbsp;</span>"+
"<div bind='containerNode' class='gmenuContainer'>&nbsp;</div>";

this.style=[
[".gmenuContainer","display: none; background-color: #ffffff; margin: 3px; padding: 3px; border: 1px solid gray;"],
[".gmenuPunkt","background-color: #ffffff; position: relative; float: left;"],
[".gmenuPunktOver","background-color: #aaaaff; position: relative; border1: 1px solid gray; float: left;"],
[".gmenuPunktActive","background-color: #00ff00; position: relative; border1: 1px solid gray; float: left;"]
];

this.r=new widget(node,params,null);
widget.call(this,node,params,null);

this.punkt.innerHTML=params.caption;
this.punkt.className="gmenuPunkt";

this.hideSibling=function()
{
if(!this.parent) return;
var arr=this.parent.children;
for(var n in arr) if((arr[n].type=="gmenu")&&(arr[n]!=this)) { arr[n].close("gmenuPunkt"); }
}

this.open=function()
{
this.active=true;
this.setStyle(null,{style: "gmenuPunktActive"});
this.containerNode.style.position="absolute";
this.containerNode.style.left=this.punkt.offsetLeft+1;
this.containerNode.style.top=this.punkt.offsetTop+this.punkt.offsetHeight;
this.containerNode.style.display="block";

if((!this.parent)||(this.parent.type!="vmenu")&&(this.parent.type!="gmenu"))addEvent(document.body,"click",this,this.bodyClick,{});
//if(this.parent) removeEvent(document.body,"click",this.parent);
}

this.close=function(newStyle)
{
this.containerNode.style.display="none"; this.active=false; this.setStyle(null,{style: newStyle});
removeEvent(document.body,"click",this);
//this.containerNode.style.display="none";
}

this.click=function(e,params)
{
this.hideSibling();
if(this.containerNode.style.display!="block") this.open();
else this.close("gmenuPunktOver");
vmenu_clk=true;
}

this.closeParents=function(obj)
{
for(var n=JSON.widgets.length-1;n>-1;n--)
if((JSON.widgets[n].type=="vmenu")||(JSON.widgets[n].type=="gmenu"))
if(JSON.widgets[n].close)
JSON.widgets[n].close.call(JSON.widgets[n],JSON.widgets[n].type+"Punkt");
}

this.bodyClick=function()
{
if(vmenu_clk) {vmenu_clk=false; return;}
else this.closeParents(this);
}

this.setStyle=function(e,params) { this.punkt.className=params.style; };

this.punktMouseOut=function(e,params)
{
if(this.active) this.setStyle(null,{style: "gmenuPunktActive"});
else this.setStyle(null,{style: "gmenuPunkt"});
}

if(!this.lastNode)addEvent(this.punkt,"click",this,this.click,{});
addEvent(this.punkt,"mouseover",this,this.setStyle,{style: "gmenuPunktOver"});
addEvent(this.punkt,"mouseout",this,this.punktMouseOut,{});
}

Это один пункт горизонтального меню (ываджвыла | .fkla fka l' | aslkdlkd).
Вертикальное отличается совсем чуть-чуть.

added later:
Цитата


dXdYdZ,

А где уверенность что этот обработчик не будет вызываться пока у меня работает само меню?


В меню при его открытии надо устанавливать флаг(переменную логического типа).
В функции закрытия (которая цепляется к document.body) надо проверять значение этого флага. Если он установлен, значит меню только что открыто и закрывать его не нужно. Нужно только сбросить флаг.
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
  kaa   smartov   dXdYdZ
advanced
Submit