【问题标题】:Override core jQuery functions on Element level在元素级别覆盖核心 jQuery 函数
【发布时间】:2011-08-11 06:17:43
【问题描述】:

是否可以在元素级别覆盖核心 jQuery 函数,例如,我想仅在一个 元素上覆盖 val() 函数。

如果我这样做

var element = $('select');
var old_val = element.val;
element.val = function () {
  console.log('The new val');
  return old_val.apply(this, arguments);
}
element.val(19);

它按预期工作,但只要我使用新的 jQuery 实例处理相同的字段

var element = $('select');
element.val(19);

它停止工作,因为我们有新的 jQuery 对象实例。如果我摆弄 $.fn.val 函数,我会更改所有支持 val 函数的对象的行为,这对我来说有点过分。

任何帮助将不胜感激。 谢谢。

【问题讨论】:

    标签: jquery function overriding element core


    【解决方案1】:

    我做了这个 jquery 扩展来做你正在谈论的事情:

    // overrides a method thats supposed to be called on a single node (a method like val)
    $.fn.overrideNodeMethod = function(methodName, action) {
        var originalVal = $.fn[methodName];
        var thisNode = this;
        $.fn[methodName] = function() {
            if (this[0]==thisNode[0]) {
                return action.apply(this, arguments);
            } else {
                return originalVal.apply(this, arguments);
            }
        };
    };
    

    对 Dave 的回答有好处 - 您不必污染 jquery 数据命名空间或担心有人覆盖该键

    【讨论】:

    • 我想知道代码中的变量arguments 来自哪里?看起来它总是未定义。或者我们可以在第四行添加$.fn[methodName] = function(arguments) { 吗?
    • @rineez arguments 是一个特殊的语言级变量,它保存传递给当前正在运行的函数的参数。在这种情况下,参数只是被传递给重写函数action 或最初定义的处理函数originalVal
    • 请注意,它会更改 jQuery 实例方法,因此实际上它不适用于“元素级别”,因为您可以拥有同一元素的多个 jQuery 实例。我对此感到非常兴奋,直到我意识到每次选择自定义元素时都必须这样做。最好将它添加到某个元素一次,然后让它的每个新 jQuery 实例都更改所需的方法。
    • 这是一个非常糟糕的主意!想象一下当你像这样覆盖循环中的 100 个元素时会发生什么 - pastebin.com/BUmmjMrE - 如果你每次调用 .val 都这样做() 将导致调用 100 个函数得到一个简单的值。
    • @Peter 为什么你会有 100 个嵌套函数覆盖?这真是个坏主意。此外,如果你有 100 个覆盖,它不会只是获得“一个简单的值”——你显然会做 100 件疯狂的事情——一个非常复杂的功能。所以不,在合理的情况下,不,我的回答不是一个糟糕的主意。
    【解决方案2】:

    基于 sdleihssirhc 的回答,但修改为仅适用于先前匹配的元素,因为您说“仅在 ​​one

    element.data('custom_val', function() {
        console.log('The new val');
    });
    
    $.fn.old_val = $.fn.val;
    $.fn.val = function () {
        var custom_val = this.data('custom_val');
        if (custom_val) {
             return custom_val.apply(this, arguments);
        } else {
             return this.old_val.apply(this, arguments);
        }
    };
    

    【讨论】:

    • 所以基本上,我仍然需要重写全局 val 函数,这将导致每次调用 val() 函数来检查当前选择的元素是否定义了 custom_val 函数是数据存储。好吧,我承认这是我偶然发现的最干净的方法。我希望有一种方法可以跳过为每个 jQuery 元素修改 val()
    • 我不相信有 - 如果您仍然希望 $("select") 第二次工作,那么您必须修改全局 val() 函数。但是这种方法可以有效地让您覆盖某些元素而不是其他元素。
    【解决方案3】:

    这个小 sn-p 允许覆盖 jQuery 方法。

    我发现@BT 的答案很糟糕,因为它在每次使用函数时都会创建额外的回调。因此,如果您将其应用于 1000 个元素,则会调用每个 val() 的 1000 个函数!

    我的overrideNodeMethod 可以根据需要多次应用于任意数量的元素。它基本上检查hasOverriddenMethod数据

    var originaljQueryMethods = {};
    for(var method in $.fn){        
        originaljQueryMethods[method] = $.fn[method];
    };
    
    $.fn.callOriginalMethod = function(method, args) {        
        return originaljQueryMethods[method].apply(this, args);
    };        
    
    $.fn.overrideNodeMethod = function(method, callback) {                
        var dataKey = "hasOverriddenMethod." + method;
        $(this).callOriginalMethod("data", [dataKey, callback]);
        $.fn[method] = function() {
            var callback = $(this).callOriginalMethod("data", [dataKey])
            if (callback) {
                return callback.apply(this, arguments);                
            }
            return $(this).callOriginalMethod(method, arguments);            
        };
    };
    

    【讨论】:

      【解决方案4】:

      每个 jQuery 对象都包含一个 selector 属性,其中包含(duh)用于获取元素的原始选择器(我根本没有真正使用过它,所以我不确定它会发生什么当您通过一系列方法时)。

      因此,您可以将val 方法包装在一个检查selector 属性的函数中,然后决定是使用您的函数还是使用原始函数。它看起来像这样:

      $.fn.old_val = $.fn.val;
      $.fn.val = function () {
          if (this.selector === 'select') {
              console.log('The new val');
          }
          return this.old_val.apply(this, arguments);
      };
      

      你以前基本上有过这个,我只是对其进行了调整,使其适用于所有新的 jQuery 实例。

      (另外,这本身就非常简单;您需要相应地修改/增强它。)

      【讨论】:

      • 这会因$("select.someClass") 等而中断。如果选择器变得更复杂,它将停止运行。你需要一个稳定的正则表达式来捕捉它。
      • 我同意这是可能的解决方案,这已经在我的脑海中浮现,但我认为这将是矫枉过正,因为我不想在全球层面上搞乱这些核心功能。我有兴趣找到在单个元素上覆盖该函数的解决方案,而不是全局 $.fn 级别
      【解决方案5】:

      是的,这是一个很好的问题。我永远不会尝试这个东西。

      我们走吧:

      在我们开始之前,我们应该将默认的 val 函数复制到另一个地方:

      jQuery.fn.oldval = jQuery.fn.val;
      

      我会编写一个全局函数来捕获 val() 函数:

      jQuery.fn.val = function(value) {
         var t = jQuery(this);
         if(t.get(0)) {
            //Check for overwritten function
            var func = jQuery.data(t.get(0), 'val-function');
            if(jQuery.isFunction(func)) {
               return func(value);
            }
         }
         //Use old function
         return jQuery(this).oldval(value);
      };
      

      之后,您可以使用以下方法为 Element-Data 设置一个函数:

      var element = jQuery(...);
      jQuery.data(element.get(0), 'val-function', function(value){
         /* Your Function here */
      });
      

      我不知道这是否有效。试试吧。这只是来自我的大脑。

      【讨论】:

      • 它有效,我可以确认,但我希望偶然发现一些不需要为所有支持 val() 的 jQuery 对象执行额外代码的解决方案
      • jQuery 没有仅覆盖元素函数的解决方案。不是我听说过的。 DATA-Function 用于元素保存数据。我认为我的解决方案是故障保存且快速。您也可以将它用于您想要覆盖的任何其他功能。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多