【问题标题】:Is there any unobtrusive way to hook into jQuery methods for triggers?是否有任何不显眼的方法来挂钩 jQuery 触发器方法?
【发布时间】:2009-01-13 18:01:22
【问题描述】:

我想知道是否有任何不显眼的方式来挂钩 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、from 和 to 传递给每个 jQuery 方法内部的触发器调用。

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    写一个“钩子”函数很容易:

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

    在调用原始函数本身之前,将使用与 original 函数相同的参数调用您提供的 wrapper 函数。

    使用示例:

    $.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"
    

    (旁注:让您的wrapper 取消对original 函数的调用也是一个简单的扩展,但这比您想要的功能更多。)

    您可以直接使用它来做您想做的事,也可以让wrapper 函数触发您以标准 jquery 方式侦听的自定义 jquery 事件。

    【讨论】:

    【解决方案2】:

    事实证明这个 hack 会奏效;我使用数据的内置 setData 触发器(以及前面提到的“挂钩”在 jQuery 的 attr 和 removeAttr 上添加功能)在 jQuery 对象上的数据对象中复制 attrs。虽然它有点脏,但我获得了挂钩数据、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);
    

    【讨论】:

      【解决方案3】:

      目前在 jQuery 中没有此事件。

      livequery plugin 可能会提供您需要的东西,例如更改课程。基本上选择器被保存,然后在 DOM 中改变选择器影响的任何更改然后调用传递的函数等。

      【讨论】:

        【解决方案4】:

        为什么不使用最简单的方法:

        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 的语法。

        【讨论】:

          【解决方案5】:

          这是对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()我不知道。

          请注意,我不容忍它的使用,这只是学术上的努力。为了填充事件参数的from 属性,您想要的内容会导致attr() 的性能损失。我们必须在写入新值之前读取旧值。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多