Вам нужно выполнить несколько шагов, чтобы это сработало.
Сначала создайте родительские функции наведения, которые будут enter()
и exit()
.Они настроены с использованием функции hover()
.Затем создайте дочерние функции enterChild()
и exitChild()
.Дети просто меняют флаг, который позволяет вам узнать, находится ли ребенок в подчинении, и, таким образом, родитель все еще считается находящимся в подчинении.
Что бы вы ни хотели сделать в функции exit()
, вы не можете сделать это.это происходит немедленно, потому что события поступают в правильном порядке для графического интерфейса, но неправильный порядок для этого конкретного случая:
enter parent
exit parent
enter child
exit child
enter parent
exit parent
Поэтому, когда вызывается ваша exit()
функция, вы можетевводите потомка сразу после, и если вы хотите что-то обработать, когда и родитель и потомок выходят, то просто действовать на exit()
наверняка будет неправильно.Обратите внимание, что браузер написан таким образом, что событие выхода всегда происходит, если произошло событие ввода.Единственное исключение может быть, если вы закроете вкладку / окно, и в этом случае они могут утратить отправку большего количества событий.
Итак, в родительской функции exit()
мы используем вызов setTimeout()
для выполнения асинхронноговызов, который произойдет после выполнения функции enter()
дочернего элемента.Это означает, что мы можем установить флаг и проверить его в асинхронной функции.
MyNamespace = {};
MyNamespace.MyObject = function()
{
var that = this;
// setup parent
jQuery(".parentDiv").hover(
function()
{
that.enter_();
},
function()
{
that.exit_();
});
// setup children
jQuery(".parentDiv .children").hover(
function()
{
that.enterChild_();
},
function()
{
that.exitChild_();
});
}
// couple variable members
MyNamespace.MyObject.prototype.parentEntered_ = false;
MyNamespace.MyObject.prototype.inChild_ = false;
MyNamespace.MyObject.prototype.enter_ = function()
{
// WARNING: if the user goes really fast, this event may not
// happen, in that case the childEnter_() calls us
// so we use a flag to make sure we enter only once
if(!this.parentEntered_)
{
this.parentEntered_ = true;
... do what you want to do when entering (parent) ...
}
};
// NO PROTOTYPE, this is a static function (no 'this' either)
MyNamespace.MyObject.realExit_ = function(that) // static
{
if(!that.inChild_)
{
... do what you want to do when exiting (parent) ...
that.parentEntered_ = false;
}
};
MyNamespace.MyObject.prototype.exit_ = function()
{
// need a timeout because otherwise the enter of a child
// does not have the time to change inChild_ as expected
setTimeout(MyNamespace.MyObject.realExit_(this), 0);
};
// detect when a child is entered
MyNamespace.MyObject.prototype.enterChild_ = function()
{
this.inChild_ = true;
this.enter_(); // in case child may be entered directly
};
// detect when a child is exited
MyNamespace.MyObject.prototype.exitChild_ = function()
{
this.inChild_ = false;
// We cannot really do this, although in case the child
// is "exited directly" you will never get the call to
// the 'exit_()' function; I'll leave as an exercise for
// you in case you want it (i.e. use another setTimeout()
// but save the ID and clearTimeout() if exit_() is not
// necessary...)
//this.exit_()
};