Элегантный способ предотвратить остановку событий сразу после запуска - PullRequest
0 голосов
/ 16 декабря 2011

Я пишу плагин jQuery, в котором события, которые запускают / останавливают плагин, являются настраиваемыми, поэтому потенциально одно и то же событие может одновременно запускать и останавливать плагин (например, нажмите для запуска и нажмите для остановки).

Это элегантный способ, в идеале не включающий тайм-ауты или отмену привязки и повторного связывания слушателей (и не слишком много флагов isPlaying, isBeingStarted и т. Д.), Чтобы гарантировать, что правильный обратный вызов называется

Ответы [ 3 ]

2 голосов
/ 16 декабря 2011

( Примечание: Когда я отправил этот ответ, в вопросе была опечатка, из-за которой казалось, что связывание / открепление будет в порядке, если не задействованы тайм-ауты.)

Я не вижу необходимости в тайм-аутах, просто привязывайте / отменяйте привязку соответствующим образом:

this.bind(startEvent, start);

function start() {
    $(this).unbind(startEvent).bind(stopEvent, stop);
}

function stop() {
    $(this).unbind(stopEvent).bind(startEvent, start);
}

В приведенном выше примере я предполагаю, что startEvent - это настроенное имя стартового события (и я, вероятно,добавьте к нему пространство имен, например, пользователь передает "click", но вы добавляете к нему ".niftyplugin", в результате чего startEvent содержит "click.niftyplugin", так что вы можете связывать / отменять привязку по желанию), а stopEvent - настроенное событие остановкиname (с пространством имен).

Вот полный пример с пространствами имен и использованием data для запоминания опций (вы можете использовать закрытие, если хотите) - живая копия :

// Plugin stuff
(function($) {
  $.fn.niftyPlugin = niftyPlugin;
  function niftyPlugin(options) {
    var data;

    data = {
      startEvent: (options && options.startEvent || "click") + ".niftyplugin",
      stopEvent: (options && options.stopEvent || "click") + ".niftyplugin"
    };

    this.data("niftyPlugin", data).bind(data.startEvent, start);

    return this;
  }

  function start() {
    var $this = $(this),
        data = $this.data("niftyPlugin");
    $this.unbind(data.startEvent).bind(data.stopEvent, stop);
    display("Start");
  }

  function stop() {
    var $this = $(this),
        data = $this.data("niftyPlugin");
    $this.unbind(data.stopEvent).bind(data.startEvent, start);
    display("Stop");
  }

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
})(jQuery);

// Use
jQuery(function($) {
  $("#theButton").click(function() {
    $("<p>Non-plugin hook fired</p>").appendTo(document.body);
  }).niftyPlugin({
    startEvent: "click"
  });
});

Единственная другая альтернатива, которую я вижу, это stopImmediatePropagation - живой пример :

// Plugin stuff
(function($) {
  $.fn.niftyPlugin = niftyPlugin;
  function niftyPlugin(options) {
    var startEvent, stopEvent, running = false;

    startEvent = (options && options.startEvent || "click") + ".niftyplugin";
    stopEvent = (options && options.stopEvent || "click") + ".niftyplugin";

    this.bind(startEvent, start).bind(stopEvent, stop);

    return this;

    function start(event) {
      if (running) {
        return;
      }
      running = true;
      display("Start");
      event.stopImmediatePropagation();
    }

    function stop(event) {
      if (!running) {
        return;
      }
      running = false;
      display("Stop");
      event.stopImmediatePropagation();
    }
  }

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
})(jQuery);

// Use
jQuery(function($) {
  $("#theButton").click(function() {
    $("<p>Non-plugin hook fired</p>").appendTo(document.body);
  }).niftyPlugin({
    startEvent: "click"
  });
});

Мне не нравитсяэто, хотя, потому что это мешает другим обработчикам для события.Например, в приведенном выше примере, если я изменю использование на следующее:

// Use
jQuery(function($) {
  $("#theButton").niftyPlugin({
    startEvent: "click"
  }).click(function() {
    $("<p>Non-plugin hook fired</p>").appendTo(document.body);
  });
});

... чтобы плагин захватывал события перед кодом, не являющимся плагином, boom , код не подключаемого модуля никогда не видит событие ( пример ).

Так что, несмотря на накладные расходы, я подозреваю, что bind / unbind - ваши друзья здесь.

0 голосов
/ 06 января 2012

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

function processEvents() {
    var tempStart = opts.startEvent.split(" ").sort(),
        tempStop = opts.stopEvent.split(" ").sort();
    startEventLoop: for(var i=0, il = tempStart.length;i<il;i++) {
        for(var j=0, jl = tempStop.length;j<jl;j++) {
            if(tempStart[i] == tempStop[j]) {
                stopStartEvents.push(tempStart[i])
                tempStop.splice(j,1);
                continue startEventLoop;
            }
        }
        startEvents.push(tempStart[i])
    }
    startEvents = startEvents.join(" ");
    stopEvents = tempStop.join(" ");
    stopStartEvents = stopStartEvents.join(" ");
}

    $this.on(stopEvents, function() {
        $this.trigger("stop.flickBook");
    }).on(startEvents, function() {
        $this.trigger("start.flickBook");
    }).on(stopStartEvents, function() {
        playing ? $this.trigger("stop.flickBook") : $this.trigger("start.flickBook");
    });
0 голосов
/ 16 декабря 2011

Это может быть излишним, но элегантный способ не поддерживать несколько флагов (например, «isPlaying») - это использовать Finite State Machine .

Вот реализация jQuery: https://github.com/DukeLeNoir/jquery-machine

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