Проблема с запуском jQuery mouseleave, когда контейнер имеет поле выбора
У меня есть два контейнера - один вложен внутри другого. Когда я наводил указатель на родителя, я хочу, чтобы появился контейнер для детей. Когда я нажимаю, я хочу, чтобы дочерний контейнер исчезал. Проблема, с которой я столкнулась, - это дочерний контейнер, имеющий форму, которая содержит "поле выбора". Когда пользователь выбирает поле выбора - случайное событие mouseleave случайно запущено.
Как я могу остановить окно выбора при отключении события mouseleave?
Здесь вы можете увидеть мой рабочий код: http://jsfiddle.net/rsturim/9TZyh/3/
Вот сводка моего script:
$('#parent-container').live("mouseenter", function () {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function (e) {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().hide();
});
edit: отображается в браузерах на основе WebKit. Ошибка в Firefox и IE7-IE9.
Ответы
Ответ 1
Так как события mouseleave и mouseenter нестандартны, вы можете получить такие задержки здесь и там. Единственный метод, который я могу предложить исправить, это использование некоторых хаков. Вот http://jsfiddle.net/mPDcu/1/ улучшенная версия вашего кода.
var selectOpened = false;
$('#select-grind-type').click(function(e){
selectOpened = !selectOpened;
e.stopPropagation();
});
$('body').click(function(){
if (selectOpened) {
selectOpened = false;
}
})
$('#parent-container').on("mouseenter", function() {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function(e) {
if (!selectOpened) {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().hide();
}
});
Ответ 2
В большинстве случаев вам просто нужно проверить, был ли целевой объект выбранным элементом, и продолжать его только в том случае, если это не так. Кажется намного чище, чем принятое решение, и хорошо работал в моем случае.
Я изменил скрипту: http://jsfiddle.net/Dygerati/uj3ZC/5/
$('#parent-container').live("mouseenter", function() {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function(e) {
if(e.target.tagName.toLowerCase() != "select") {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().hide();
}
});
Ответ 3
$('#parent-container').live("mouseenter", function () {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function (e) {
/* Solution */
if(e.relatedTarget == null) return;
/************/
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().hide();
});
Ответ 4
У меня была та же проблема в проекте, в котором я вношу свой вклад, а другие ответы не сработали для меня. Моим сложным решением было проверить, находится ли позиция мыши внутри объекта события внутри родительского контейнера. Работает очень хорошо!
var layer = $('#parent-container'),
layerPos = {};
$(layer).mouseenter(function () {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().fadeTo('slow', 1.0, function(){
layerPos.x = {
min: $(layer).offset().left,
max: $(layer).offset().left + $(layer).width()
};
layerPos.y = {
min: $(layer).offset().top,
max: $(layer).offset().top + $(layer).height()
};
});
})
$(layer).mouseleave(function(e) {
// check if event mouse position is inside parent container
var x_con = e.pageX >= layerPos.x.min && e.pageX <= layerPos.x.max;
var y_con = e.pageY >= layerPos.y.min && e.pageY <= layerPos.y.max;
if ( x_con && y_con ) {
return false;
}
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().hide();
});
Вы также можете проверить версию навигатора, чтобы этот код не выполнялся в браузерах, поддерживающих такие функции, как Chrome.
Ответ 5
Это частично решает проблему.
Отвяжите событие mouseleave
, когда поле выбора получает фокус и снова связывается, когда оно теряет фокус.
http://jsfiddle.net/9TZyh/5/
$('#parent-container').live("mouseenter", function() {
var $this = $(this);
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave",focusOut);
$("#select-grind-type").live("focus",function(){
$('#parent-container').die("mouseleave");
});
$("#select-grind-type").live("focusout change",function(){
$('#parent-container').live("mouseleave",focusOut);
});
function focusOut(e) {
var $this = $(this),
$selectOptionsContainer = $this.find('#child-container');
$selectOptionsContainer.stop().hide();
}
Ответ 6
Эти ребята дают вам рабочую альтернативу, но у нее также есть некоторые ошибки. Например, если вы выходите из внешнего поля, когда выпадающее поле все еще открыто, оно не будет исчезать. Я рекомендую вам гораздо более легкую альтернативу, которая также устранит эту ошибку.
Вместо того, чтобы думать в событии mouseleave внутреннего поля, почему бы вам не поразмыслить, чтобы думать наоборот? Я имею в виду, оставляя внутреннюю коробку, а также означает вхождение в другой контейнер. Итак, вы можете сделать outerContainer.mouseenter(function(){ hideInnerBox() });
: -)
Очевидно, что для этой цели внутренний ящик не должен быть дочерним элементом outerbox, даже если визуально это выглядит так (для достижения его можно использовать позиционирование css)
Ответ 7
Если вы не возражаете, если в некоторых старых браузерах fade не работает, вы можете быстро сделать это с помощью CSS:
#parent-container { }
#child-container {
opacity:0;
-webkit-transition:opacity 1s ease-in;
-moz-transition:opacity 1s ease-in;
}
#parent-container:hover #child-container {{
opacity:1;
-webkit-transition:opacity 1s ease-out;
-moz-transition:opacity 1s ease-out;
}
Ответ 8
Итак, я просто столкнулся с аналогичной проблемой с <select>
, вложенной в контейнер, и наткнулся на этот вопрос. Вот что я сделал.
$("#container").mouseover(function(e){
var t = $(this);
t.addClass('active');
var offset = t.offset();
var xMin = offset.left;
var yMin = offset.top;
var xMax = xMin + t.innerWidth();
var yMax = yMin + t.innerHeight();
t.parent().mousemove(function(e){
if(e.pageX < xMin || e.pageX > xMax-2 || e.pageY < yMin || e.pageY > yMax ){
t.removeClass('active');
// unbind this event
$(this).unbind('mousemove');
}
});
});
В принципе, когда вы наводите указатель мыши на контейнер, мы собираем его границы и начинаем проверять, находится ли мышь над элементом. Когда мы знаем, что мышь ушла, мы отвязываем слушателя mousemove
.
Я бы сделал jsfiddle для вас, но сейчас он работает так медленно!
Надеюсь, что это поможет.
Ответ 9
Вы должны только проверить, является ли текущий элемент потоком вашего контейнера.
Если это прервано обработчик.
Смотрите: потомок jquery
Пример:
ContainerElement.mouseleave(function (e) {
if (ContainerElement.has(e.fromElement).length > 0) return;
// Do your Stuff
});