我希望所有按钮在正常的onclick事件之前和之后执行操作。所以我提出了循环遍历所有这些元素并创建包装函数的“精彩”想法。
当我测试它时,这看起来效果很好,但是当我将它集成到我们的应用程序中时,它就崩溃了。我追溯到'this'值被我的包装器改变了。示例代码说明了这一点;在包装事件处理程序之前,每个按钮在您单击时显示按钮ID,但在包装后,显示的名称在此示例中为“undefined”,如果从表单中运行,则为“Form1”。
有没有人知道做同样事情的更好方法?或者是保持最初预期的“这个”价值的好方法?
您可以想象,我不想修改目标按钮中的任何现有事件处理程序代码。
提前致谢。
PS-目标浏览器是IE6& up,不需要crossbrowser功能
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<script language="javascript" type="text/javascript">
function btnWrap_onClick()
{
var btns = document.getElementsByTagName("button");
for( var i = 0; i < btns.length; i++)
{
var btn = btns[i];
// handle wrap button differerntly
if( "btnWrap" == btn.id)
{
btn.disabled = true;
continue; // skip this button
}
// wrap it
var originalEventHandler = btn.onclick;
btn.onclick = function()
{
alert("Starting event handler");
originalEventHandler();
alert("Finished event handler");
}
}
alert("Buttons wrapped successfully");
}
</script>
<body>
<p>
<button id="TestButton1" onclick="alert(this.id);">TestButton1</button>
<button id="TestButton2" onclick="alert(this.id);">TestButton2</button>
</p>
<button id="btnWrap" onclick="btnWrap_onClick();">Wrap Event Handlers</button>
</body>
</html>
答案 0 :(得分:4)
您可以使用call方法解析绑定,例如originalEventHandler.call(btn);
或者,类似原型的库可以提供帮助 - 它的bind方法允许您构建绑定到指定对象的新函数,因此您已将originalEventHandler声明为var originalEventHandler = btn.onclick.bind(btn);
最后,关于绑定问题的良好背景,请参阅Getting Out of Binding Situations in JavaScript
答案 1 :(得分:3)
如Paul Dixon所述,您可以使用call,但我建议您改用apply。
然而,我回答的原因是我发现了一个令人不安的错误:您实际上是用最后一个按钮的事件处理程序替换所有事件处理程序。我不认为那是什么你打算,是吗? (提示:您正在每次迭代中替换originalEventHandler的值)
在下面的代码中,您可以找到一个有效的跨浏览器解决方案:
function btnWrap_onClick()
{
var btns = document.getElementsByTagName("button");
for( var i = 0; i < btns.length; i++)
{
var btn = btns[i];
// handle wrap button differerntly
if( "btnWrap" == btn.id)
{
btn.disabled = true;
continue; // skip this button
}
// wrap it
var newOnClick = function()
{
alert("Starting event handler");
var src=arguments.callee;
src.original.apply(src.source,arguments);
alert("Finished event handler");
}
newOnClick.original = btn.onclick; // Save original onClick
newOnClick.source = btn; // Save source for "this"
btn.onclick = newOnClick; //Assign new handler
}
alert("Buttons wrapped successfully");
}
首先,我创建一个新的匿名函数并将其存储在变量 newOnClick 中。由于函数是一个对象,我可以像任何其他对象一样在函数对象上创建属性。我使用它来创建属性原始,它是原始的onclick-handler,而 source 是源元素,它将是 this 调用原始处理程序。
在匿名函数内部,我需要获取对函数的引用,以便能够获取属性原始和源的值。由于匿名函数没有名称,我使用arguments.callee(自MSIE5.5以来一直支持)来获取该引用并将其存储在变量src中。
然后我使用方法 apply 来执行原始的onclick处理程序。 apply 有两个参数:第一个是 this 的值,第二个是参数数组。 此必须是附加原始onclick处理程序的元素,并且该值保存在 source 中。 arguments 是所有函数的内部属性,并保存调用函数的所有参数(请注意,匿名函数没有指定任何参数,但如果使用某些参数调用它们,它们是将在参数属性中找到。
我使用 apply 的原因是我可以转发所有调用匿名函数的参数,这使得此函数透明且跨浏览器。 (Microsoft将事件放在window.event中,但其他浏览器在处理程序调用的第一个参数中提供它)
答案 2 :(得分:1)
你的问题是关闭JavaScript的工作方式。老实说,我建议使用框架。他们中的任何一个都应该使事件处理远比手工操作好得多。