Выполнить функцию после задержки или убить ее в jquery

98
9

Я использую функцию для загрузки страницы с помощью jQuery, но только после некоторой задержки после зависания над li. Для этого я использую setTimeout на mouseover и попытаться убить его на mouseleave, если мышь зависла менее 500мс над li. Тем не менее, jQuery.ajax прежнему запускается, поэтому в принципе, если я нахожусь над всеми li, это запустит много xhr, даже если я оставлю только 1 мс на li.

var timer2;
var delay2 = 500;

$('body').on('mouseover','li',function(){

timer2 = setTimeout(function() {

var url="res.php";
jQuery.ajax(
{
type: 'POST',
url:url,
success: function(data){

$('#res').html(data);

}
});

}, delay2);

});
$('body').on('mouseleave', 'li', function() {
clearTimeout(timer2);
});

спросил(а) 2018-01-09T19:22:00+03:00 2 года, 8 месяцев назад
1
Решение
80

Проблема здесь проста. Вы используете mouseover, mouseover может запускать несколько setTimeouts, пока вы находитесь над элементом.

$("div")
.on("mouseover", function(){ console.log("mouseover"); })
.on("mouseenter", function(){ console.log("mouseenter"); });
span { background-color: red;
font-size: 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<span>Move mouse here</span> to <span>here</span> to <span>here</span></div>

Поэтому каждый раз, когда вы перемещаете элементы внутри родителя, он запускает другое наведение. Поэтому, если это так, вы создадите несколько событий. Поэтому, если вы видите несколько вызовов ajax для li, это может быть причиной.

Поэтому измените его на mouseenter, затем отмените событие внутри входа или отслеживайте события через сам лидж, а не глобальный.

$("ul")
.on("mouseenter", "li" function(){
$(this).data("timer", setTimeout( function () {});
}).on("mouseleave", "li" function(){
var id = $(this).data("timer");
if (id) window.clearTimeout(id);
})

И если вы действительно хотите быть уверенным, очистите тайм-аут на mouseenter....

ответил(а) 2018-01-09T19:46:00+03:00 2 года, 8 месяцев назад
79

Просто очистите время ожидания перед его настройкой:

var timer2 = null;

$('body').on('mouseover','li',function(){
clearTimeout(timer2);
timer2 = setTimeout(function(){ .....

Вам нужно инициализировать таймаут до null, иначе вы получите сообщение об ошибке, can't clear timeout of undefined.

Кроме того, попробуйте это, чтобы вызвать mouseleave:


$('body').on('mouseover','li',function(){
// ...
$(this).off("mouseleave").on("mouseleave", () => clearTimeout(timer2))
});

Изменение: рабочий фрагмент

var timer2 = null;
var delay2 = 2000;

$('body').on('mouseover', 'li', function() {
clearTimeout(timer2);
console.log("Setting timeout...")

timer2 = setTimeout(() => console.log("Ajax call!"), delay2);

$(this).off("mouseleave").on('mouseleave', () => {
console.log("Clearing timeout.")
clearTimeout(timer2);
});
});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<li>Hover over me</li>
<li>Over me too</li>

ответил(а) 2018-01-09T19:29:00+03:00 2 года, 8 месяцев назад
-4

Существует несколько способов решения этой проблемы

abort ваш запрос после mouseleave используйте переменную внутри обратного вызова, чтобы сказать "не делай этого", abort запрос
// ...
var request;

$('body').on('mouseover','li',function(){
// ... I omited 'setTimeout' to simplify the explanation
// you have to make this variable to be able to control your requests
var xhr = new window.XMLHttpRequest();
// here we save our request
request = jQuery.ajax(
{
// ...
// note this change here, it is required for jquery 3.0 and more
xhr : function(){ return xor; }
});
// ...

});
$('body').on('mouseleave', 'li', function() {
// ...
// now we can 'abort' it any time user mouse leaves
request.abort();
});

Вопрос о прерывании на SO

использовать переменную
// ...
var leaved = false

$('body').on('mouseover','li',function(){
// ... I omited 'setTimeout' to simplify the explanation
leaved = false
jQuery.ajax(
{
// ...
success: function(data){
if (leaved) return;
$('#res').html(data);

}
});
// ...

});
$('body').on('mouseleave', 'li', function() {
// ...
leaved = true
});

ответил(а) 2018-01-09T19:49:00+03:00 2 года, 8 месяцев назад
-4

Дайте id этому конкретному li и используйте, как показано ниже. Это работает. Отметьте вкладку console Networks для проверки.

var timer2;
var delay2 = 500;
var ajax;
$('body').on('mouseover','li#one',function(){
console.log("Mouse over");
clearTimeout(timer2);
timer2 = setTimeout(function() {
if(ajax) {ajax.abort();}
var url="res.php";
ajax = $.ajax(
{
type: 'POST',
url:url,
async:true,
success: function(data){
$('#res').html(data);
}
});
}, delay2);

});
$('body').on('mouseleave', 'li#one', function() {
console.log("Mouse left");
clearTimeout(timer2);
});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li id="one">One</li>
<li>Two</li>

ответил(а) 2018-01-09T19:40:00+03:00 2 года, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема