Есть ли какой-нибудь ненавязчивый способ подключиться к методам jQuery для триггеров? - PullRequest
2 голосов
/ 13 января 2009

Мне было интересно, есть ли какой-нибудь ненавязчивый способ подключиться к таким методам, как attr, data, css и т. Д. И вызвать пользовательские триггеры?

В идеале я мог бы сделать что-то вроде этого:

$(".friend a").bind("attr.changed", changed /* data */, function(e) {
    alert("The " + changed.attribute + " attribute changed from " + changed.from + " to " + changed.to + "!");
});

$(".friend").append(
  $("<a/>").
    attr("href", "#").
    html("Friend 1").
    click(function() { alert('I was clicked!'); }); // creates the element, doesn't execute since element didn't exist

$(".friends a").each(function() {
  var $this = $(this);
  $this.attr("rel", "friend"); // triggers "attr.changed"
});

В идеале это можно было бы запустить на любом элементе и передать измененное значение attr от и до объекта в вызов триггера внутри каждого метода jQuery.

Ответы [ 5 ]

7 голосов
/ 13 января 2009

Довольно просто написать функцию «крючка»:

function hook(original, wrapper) {
    return function() {
        wrapper.apply(this, arguments);
        return original.apply(this, arguments);
    }
}

Предоставленная вами функция wrapper будет вызываться с теми же аргументами, что и функция original, до вызова самой исходной функции.

Пример использования:

$.fn.attr = hook($.fn.attr, function(attribute, value) {
    alert('attribute: '+attribute+', value: '+value);
});
$('a.pie').attr('href', 'http://blueberry.pie');
// An alert says "attribute: href, value: http://blueberry.pie"

(Sidenote: Было бы легко позволить вашему 1011 * отменить вызов функции original, но это становится более функциональным, чем вы хотели.)

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

1 голос
/ 14 января 2009

Оказывается, этот хак будет работать; Я использую встроенные триггеры данных setData (и вышеупомянутый «хук», чтобы добавить функциональность поверх attr и removeAttr jQuery) для дублирования attrs в объекте данных объекта jQuery. Хотя это несколько грязно, я получаю функциональность, позволяющую подключаться к триггерам изменения данных для data, attr и, если они пишутся, любых других методов jQuery, которые отслеживают пары ключ / значение.

(function($) {
  var binder = function(e, dataKey, dataValue) {
    return (function(dataKey, dataValue, self) {
      var $this = $(self),
          oldValue = $this.data(dataKey),
          newValue = dataValue,
          passed = {
            attr: dataKey,
            from: oldValue,
            to:   newValue
          };

      var isAttribute = !!($this.data(dataKey + "-attribute"));

      if(oldValue !== newValue) { 
        var attrPrefix = isAttribute ? "attr-" : "";
        $this.trigger(attrPrefix + dataKey + "-changed", passed); 
        $this.trigger(attrPrefix + "data-changed", passed); 
      }
    })(dataKey, dataValue, this);
  };

  var hook = function(original, wrapper) {
    return function() {
      wrapper.apply(this, arguments);
      return original.apply(this, arguments);
    };
  };

  $.fn.attr = hook($.fn.attr, function(attr, val) {
    if(val) {
      $(this).data(attr + "-attribute", true);
      $(this).data(attr, val);
    }
  });

  $.fn.removeAttr = hook($.fn.removeAttr, function(attr) {
    $(this).removeData(attr + "-attribute");
    $(this).removeData(attr);
  });

  $.fn.observeData = function() {
    $(this).bind("setData", binder);
  };
})(jQuery);
0 голосов
/ 13 января 2009

А почему бы вам не использовать самый простой подход:

jQuery.fn.changeAttr = function(attrName,attrValue) {
  return this.each(function(){
    this.attr(attrName,attrValue);
    alert('The att: '+attrName+ ' is now '+attrValue);
  });
};

А потом просто:

$('.friends a').changeAttr('rel','friend')

Извините, если это не работает, я не помню точно синтаксис для расширения jQuery.

0 голосов
/ 13 января 2009

Вот модификация attr() в соответствии с тем, о чем вы говорите.

(function(attr) {

    jQuery.attr = function(elem, name, value) {
        var current = attr(elem, name, undefined); // read current value
        var retval = current;

        if (value !== undefined) { // writing
            retval = attr(elem, name, value); // call original
            jQuery.event.trigger('attr.changed', {
                attribute: name,
                from: current,
                to: value
            }, elem)
        }

        return retval; // return original
    }

})(jQuery.attr);

Использование должно быть:

$(".friend a").bind("attr.changed", function(e, changed) {
    alert("The " + changed.attribute + " attribute changed from " + changed.from + " to " + changed.to + "!");
});

$(".friends a").attr("class", "foo"); // triggers alert

Я не верю, что css() возможно, поскольку свойство .style не может вызывать события. data() Я не знаю.

Заметьте, я не одобряю его использование, это было просто академическое усилие. То, что вы хотите, влечет за собой снижение производительности на attr(), чтобы заполнить свойство from аргумента события. Мы должны прочитать старое значение, прежде чем писать новое.

0 голосов
/ 13 января 2009

Нет событий для этого в настоящее время существует в jQuery.

Плагин livequery может предоставить что-то из того, что вам нужно, например, изменение классов. В основном селектор сохраняется, а затем любые изменения в DOM, которые изменяют то, на что влияет селектор, затем вызывают переданные функции и т. Д.

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