Выполнить функцию после задержки или убить ее в jquery
Я использую функцию для загрузки страницы с помощью 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);
});
Проблема здесь проста. Вы используете 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....
Просто очистите время ожидания перед его настройкой:
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>
Существует несколько способов решения этой проблемы
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();
});
использовать переменную // ...
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
});
Дайте 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>