Export to GitHub

jquery-debounce - issue #1

Теряется контекст для обработчиков событий, привязанных к элементам через jQuery


Posted on Aug 23, 2009 by Grumpy Camel

Дим, в рамках своего кода и использования jQuery 1.3.2 я нашел в твоих функциях, в моем случае, существенный недостаток. Суть в том, что при биндинге обработчика события через обертку одной из твоих функций, в теле обработчика перестает быть доступной переменная this. Опишу на примере:

У меня есть обработчик события для hover:

<pre> var onHover = function() { $(this).addClass('hover'); }, onLeave = function() { $(this).removeClass('hover'); }; </pre>

Как известно при биндинге обработчиков jQuery контекстом выполнения функции является DOM элемент, породивший событие.

Биндинг: $('.i-have-hover').hover( onHover, onLeave );

Пример выше работает, но как только мы обернем один из обработчиков функциями throttle или debounce, то код перестанет работать из-за отсутствия контекста.

При это мы не можем указать контекст в обертке, т.к., естественно, не знаем его.

Что-то мне подсказывает, что следующий код не будет работать так, как нужно, т.к. на каждое событие throttle вернет новую функцию со своим персональным таймером.

<pre> $('.i-have-hover').hover(function() { $.throttle(onHover, 300)(); }); </pre>

Соответственно выход один: исправить ситуация в коде плагина. Тут можно пойти двумя путями:

Первый, который я реализовал и мне он больше нравится, но на данный момент у меня нет времени подумать глубже, может быть он и плох, поэтому ниже есть второй :)

И так изменения к плагину: поскольку каждая функция (throttle, debounce) возвращает указатель на вновь созданную функцию, то в теле этой новой функции я добавляю переменную ctx:

<pre> var ctx = context || this; </pre>

Она заполняется либо указанным при инициализации обретки контекстом, либо контекстом, в котором вызывают нашу обертку. Далее в вызове самой функции, которую оборачивали, я указываю контекстом выполнения переменную ctx вместо context.

Пример для throttle:

<pre> throttle: function(fn, timeout, context) { var timer;

return function() {
    var args = arguments, ctx = context || this;

    if (!timer) {
        (function() {
            if (args) {
                fn.apply(ctx, args);
                args = null;
                timer = 

setTimeout(arguments.callee, timeout); } else { timer = null; } })(); } }; } </pre>

Во втором варианте я предлагаю создать объект-хеш, в котором хранить таймеры для оборачиваемых функций. Но тут нужно подумать, я не рассматривал этот вариант глубоко.

Спасибо за внимание :)

Кстати, исправленный исходник в аттаче.

Attachments

Comment #1

Posted on Feb 24, 2010 by Happy Dog

(No comment was entered for this change.)

Status: Fixed

Labels:
Type-Defect Priority-Medium