在元素级别覆盖核心 jQuery 函数
Posted
技术标签:
【中文标题】在元素级别覆盖核心 jQuery 函数【英文标题】:Override core jQuery functions on Element level 【发布时间】:2011-08-11 06:17:43 【问题描述】:是否可以,例如,我想仅在一个 元素上覆盖 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 函数的对象的行为,这对我来说有点过分。
任何帮助将不胜感激。 谢谢。
【问题讨论】:
【参考方案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 用于元素保存数据。我认为我的解决方案是故障保存且快速。您也可以将它用于您想要覆盖的任何其他功能。以上是关于在元素级别覆盖核心 jQuery 函数的主要内容,如果未能解决你的问题,请参考以下文章