YUI: остановить обработчики событий от запуска во время анимации - PullRequest
1 голос
/ 05 августа 2011

Итак, я использую YUI для добавления анимации в мое приложение, которая запускается, когда пользователь нажимает определенные элементы. Тем не менее, я сталкиваюсь с общей проблемой, которая легко решается при плохом кодировании, но я ищу более элегантное решение, которое менее подвержено ошибкам.

Часто, когда пользователь что-то щелкает, элемент DOM анимируется (используя Y.Anim), и я подписываюсь на событие end этой анимации, чтобы удалить элемент из документа после его анимации. Довольно стандартные вещи.

Однако проблемы возникают, когда пользователь решает щелкнуть спам по элементу, который вызывает это событие. Если элемент будет удален из DOM, когда анимация закончится, и пользователь запустит обработчик событий, который запускает ДРУГУЮ анимацию на том же элементе, эта 2-я анимация в конечном итоге приведет к тому, что YUI будет выплевывать действительно неприятные ошибки, потому что узел был анимация внезапно исчезла из документа. Самое быстрое решение, которое я нашел для этого, состоит в том, чтобы просто установить какое-либо логическое состояние уровня модуля / класса, например, this.postAnimating или что-то в этом роде, и внутри обработчика событий, запускающего анимацию, проверить, установлено ли для этого значение true, и если так что ничего не делай. В обработчике 'end' для анимации установите для этого состояния значение false.

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

Какой элегантный и надежный способ решить эту проблему, не испортив файл Javascript из нескольких тысяч строк с кусочками и кусочками состояния?

Вот пример кода, описывающего проблему и мое решение.

var popupShowing = false,
    someElement  = Y.one('...');

someElement.on("click", showPopUp)

var showPopup = function(e) {
    if(!popupShowing) {
      popupShowing = true;
      var a = new Y.Anim({
          node: someElement,
          duration: 0.2,
          ...
      });

      a.on('end', function() {
          someElement.remove(true);
          popupShowing = false;
      });

      a.run();
    }
}

Так что, если пользователь нажимает «someElement» много раз, срабатывает только одна анимация. Если бы я не использовал popupShowing в качестве защиты, многие анимации на одном и том же узле были бы запущены, если пользователь щелкнул достаточно быстро, но последующие из них выдали бы ошибку, потому что someElement был удален при первом завершении.

Ответы [ 3 ]

1 голос
/ 06 августа 2011

Посмотрите на API перехода. Это более кратко, и вполне может сделать то, что вы хотите из коробки.

someElement.transition({ opacity: 0, duration: 0.2 }, function () { this.remove(); });
// OR
someElement.on('click', function () { this.hide(true, { duration: 0.2 }); });
// OR
someElement.on('click', someElement.hide);

Лично я не использовал Anim с тех пор, как Transition был добавлен в 3.2.0. Transition использует CSS3 там, где поддерживается (с аппаратным ускорением), и возвращается к JS-таймеру для старых браузеров. http://developer.yahoo.com/yui/3/examples/transition/transition-view.html

0 голосов
/ 01 сентября 2011

Быстрое и грязное решение этой конкретной проблемы?

Присоедините ваши обработчики, используя .once () вместо

someElement.once("click", showPopUp)

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

Кроме того, +1 к предложению Люка использовать анимацию свойства перехода для DOM, это здорово.

0 голосов
/ 05 августа 2011

Редактировать: По многочисленным просьбам, способ YUI:

myAnim.get('running')

сообщает вам, запущена ли анимация. Чтобы использовать это, вам, возможно, придется реструктурировать способ вызова события, чтобы анимация находилась в нужной области, например:

YUI().use('anim', function (Y) {
   var someElement = Y.one('...');
   var a = new Y.Anim({
       node: someElement,
       duration: 0.2,
       ...
   });

   a.on('end', function() {
       someElement.remove(true);
   });

   someElement.on('click', function() {
       if (!a.get('running')) {
           a.run();
       }
   });
});

Пример jsFiddle

Ранее я уже говорил: Мне лично нравится, как jQuery справляется с этим. В jQuery у каждого элемента есть очередь для функций анимации. Во время анимации страж «в процессе» выдвигается вперед на время анимации, поэтому все, кто не хочет наступать на анимацию, заглядывает в начало очереди для «в процессе» и решает, что делать дальше например, ничего не делать, встать в очередь, выгрузить текущую анимацию и т. д.

Я недостаточно знаю о YUI, чтобы рассказать вам, как реализовать это, но Я считаю, что это очень элегантное решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...