调用跨框架时,Javascript 事件在闭包中未正确设置
我在两帧页面的顶部框架中有以下代码:
function setKeyHook()
{
logMessage("setKeyHook()");
top.frames.BOTTOM.document.onkeydown =
top.frames.TOP.document.onkeydown = function( evt )
{
return function(){
top.frames.TOP.handleKeypress(evt);
};
}( window.event );
}
onload = setKeyHook;
这适用于原始文档加载,但是当我从另一个框架调用此函数时(通常仅重新加载一个框架时),会设置挂钩,但是当 < code>onkeydown 函数触发,它没有收到适当的参数,而是 evt == null
。
完整代码如下:
KeyFrameTest.asp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<title>KeyFrameTest</title>
</head>
<frameset Rows="80%,20%">
<frame id="TOP" name="TOP" src="KeyFrameTestTop.asp">
<frame id="BOTTOM" name="BOTTOM" src="KeyFrameTestBottom.asp">
</frameset>
</html>
KeyFrameTestTop.asp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<script type="Text/Javascript">
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g,"");
}
NumElements = 5;
//Alt Vals
ControlCode = 1;
ShiftCode = 2;
ControlShiftCode = 3;
//Key Vals
keyR = 82;
keyJ = 74;
keyI = 73;
keyT = 84;
keyEnter = 13;
//Array Indexs
AltIndex = 0;
KeyIndex = 1;
FuncIndex = 2;
KeyFuncMap = new Array(NumElements);
for (i = 0; i < KeyFuncMap.length; ++i)
{
//Three elements, control or shift, key, function
KeyFuncMap[i] = new Array(3);
}
KeyFuncMap[0][AltIndex] = ControlCode;
KeyFuncMap[0][KeyIndex] = keyR;
KeyFuncMap[0][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + R\")";
KeyFuncMap[1][AltIndex] = ControlCode;
KeyFuncMap[1][KeyIndex] = keyJ;
KeyFuncMap[1][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + J\")";
KeyFuncMap[2][AltIndex] = ControlCode;
KeyFuncMap[2][KeyIndex] = keyI;
KeyFuncMap[2][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + I\")";
KeyFuncMap[3][AltIndex] = ControlCode;
KeyFuncMap[3][KeyIndex] = keyT;
KeyFuncMap[3][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + T\")";
KeyFuncMap[4][AltIndex] = ControlCode;
KeyFuncMap[4][KeyIndex] = keyEnter;
KeyFuncMap[4][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + Enter\")";
function CompleteEvent(e)
{
e.cancelBubble = true;
e.returnValue = false;
}
function logMessage(msg)
{
logBox = parent.TOP.document.getElementById("logBox");
if( logBox.value.trim().length < 1 )
{
logBox.value = msg;
}
else
{
logBox.value = logBox.value + "\r\n" + msg;
}
}
function handleKeypress(e)
{
logMessage("handleKeypress(e)");
e = e || window.event ;
if (e == null)
{
logMessage("handleKeypress(e): e == null");
return false;
}
controlVal = getControlVal(e);
for (i = 0; i < KeyFuncMap.length; i++)
{
if (KeyFuncMap[i][AltIndex] == controlVal &&
KeyFuncMap[i][KeyIndex] == e.keyCode)
{
eval(KeyFuncMap[i][FuncIndex]);
CompleteEvent(e);
}
}
}
function getControlVal(e)
{
if (e.ctrlKey && e.shiftKey)
{
return 3;
}
else if (e.ctrlKey)
{
return 1;
}
else if (e.shiftKey)
{
return 2;
}
else return 0;
}
function displayEverything()
{
displayProps(top.frames.TOP, "top.frames.TOP", 0, 1);
displayProps(top.frames.BOTTOM, "top.frames.BOTTOM", 0, 1);
}
function clearLog()
{
logBox = parent.TOP.document.getElementById("logBox");
logBox.value = "";
}
function displayProps(o, name, level, maxLevel)
{
try {
if (level > maxLevel)
return;
for (prop in o){
logMessage(name + "." + prop + " = " + o[prop]);
if (typeof(o[prop]) == "object" && o[prop] != o){
displayProps(o[prop], name + "." + prop, level + 1, maxLevel);
}
}
}
catch (ex){
logMessage(ex.toString());
}
}
function setKeyHook()
{
logMessage("setKeyHook()");
top.frames.BOTTOM.document.onkeydown =
top.frames.TOP.document.onkeydown = function( evt )
{
return function(){
top.frames.TOP.handleKeypress(evt);
};
}( window.event );
}
onload = setKeyHook;
</script>
</head>
<body>
<h1>Hello</h1>
<textarea id="LogBox" rows="20" cols="80"></textarea><BR>
<input type="Button" value="Display Properties" onClick="displayEverything();"/>
<input type="Button" value="Clear Log" onClick="clearLog();"/>
</body>
</html>
KeyFrameTestBottom.asp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
</head>
<body>
<p>Press Keys Here</p>
<input type="Button" value="Reset Handlers"
onclick="top.frames.TOP.setKeyHook();">
</body>
</html>
要重新创建问题,请右键单击底部框架,单击刷新,单击“重置 Hooks”,然后按键。
相关问题: Handle keyPress Accross Frames in IE
我还读过一篇文章关于 Javascript 闭包,但我不确定它如何应用。
抱歉问题太狭隘了,但我真的不太了解 Javascript,无法找出其中的技巧。
I have the following code in the top frame of a two frame page:
function setKeyHook()
{
logMessage("setKeyHook()");
top.frames.BOTTOM.document.onkeydown =
top.frames.TOP.document.onkeydown = function( evt )
{
return function(){
top.frames.TOP.handleKeypress(evt);
};
}( window.event );
}
onload = setKeyHook;
This works on the original document load, but when I call this function from another frame (usually when only one frame reloads), the hook is set, but when the onkeydown
function fires, it does not receive the appropriate arguments, instead evt == null
.
Full Code follows:
KeyFrameTest.asp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<title>KeyFrameTest</title>
</head>
<frameset Rows="80%,20%">
<frame id="TOP" name="TOP" src="KeyFrameTestTop.asp">
<frame id="BOTTOM" name="BOTTOM" src="KeyFrameTestBottom.asp">
</frameset>
</html>
KeyFrameTestTop.asp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<script type="Text/Javascript">
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g,"");
}
NumElements = 5;
//Alt Vals
ControlCode = 1;
ShiftCode = 2;
ControlShiftCode = 3;
//Key Vals
keyR = 82;
keyJ = 74;
keyI = 73;
keyT = 84;
keyEnter = 13;
//Array Indexs
AltIndex = 0;
KeyIndex = 1;
FuncIndex = 2;
KeyFuncMap = new Array(NumElements);
for (i = 0; i < KeyFuncMap.length; ++i)
{
//Three elements, control or shift, key, function
KeyFuncMap[i] = new Array(3);
}
KeyFuncMap[0][AltIndex] = ControlCode;
KeyFuncMap[0][KeyIndex] = keyR;
KeyFuncMap[0][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + R\")";
KeyFuncMap[1][AltIndex] = ControlCode;
KeyFuncMap[1][KeyIndex] = keyJ;
KeyFuncMap[1][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + J\")";
KeyFuncMap[2][AltIndex] = ControlCode;
KeyFuncMap[2][KeyIndex] = keyI;
KeyFuncMap[2][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + I\")";
KeyFuncMap[3][AltIndex] = ControlCode;
KeyFuncMap[3][KeyIndex] = keyT;
KeyFuncMap[3][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + T\")";
KeyFuncMap[4][AltIndex] = ControlCode;
KeyFuncMap[4][KeyIndex] = keyEnter;
KeyFuncMap[4][FuncIndex] = "parent.TOP.logMessage(\"Ctrl + Enter\")";
function CompleteEvent(e)
{
e.cancelBubble = true;
e.returnValue = false;
}
function logMessage(msg)
{
logBox = parent.TOP.document.getElementById("logBox");
if( logBox.value.trim().length < 1 )
{
logBox.value = msg;
}
else
{
logBox.value = logBox.value + "\r\n" + msg;
}
}
function handleKeypress(e)
{
logMessage("handleKeypress(e)");
e = e || window.event ;
if (e == null)
{
logMessage("handleKeypress(e): e == null");
return false;
}
controlVal = getControlVal(e);
for (i = 0; i < KeyFuncMap.length; i++)
{
if (KeyFuncMap[i][AltIndex] == controlVal &&
KeyFuncMap[i][KeyIndex] == e.keyCode)
{
eval(KeyFuncMap[i][FuncIndex]);
CompleteEvent(e);
}
}
}
function getControlVal(e)
{
if (e.ctrlKey && e.shiftKey)
{
return 3;
}
else if (e.ctrlKey)
{
return 1;
}
else if (e.shiftKey)
{
return 2;
}
else return 0;
}
function displayEverything()
{
displayProps(top.frames.TOP, "top.frames.TOP", 0, 1);
displayProps(top.frames.BOTTOM, "top.frames.BOTTOM", 0, 1);
}
function clearLog()
{
logBox = parent.TOP.document.getElementById("logBox");
logBox.value = "";
}
function displayProps(o, name, level, maxLevel)
{
try {
if (level > maxLevel)
return;
for (prop in o){
logMessage(name + "." + prop + " = " + o[prop]);
if (typeof(o[prop]) == "object" && o[prop] != o){
displayProps(o[prop], name + "." + prop, level + 1, maxLevel);
}
}
}
catch (ex){
logMessage(ex.toString());
}
}
function setKeyHook()
{
logMessage("setKeyHook()");
top.frames.BOTTOM.document.onkeydown =
top.frames.TOP.document.onkeydown = function( evt )
{
return function(){
top.frames.TOP.handleKeypress(evt);
};
}( window.event );
}
onload = setKeyHook;
</script>
</head>
<body>
<h1>Hello</h1>
<textarea id="LogBox" rows="20" cols="80"></textarea><BR>
<input type="Button" value="Display Properties" onClick="displayEverything();"/>
<input type="Button" value="Clear Log" onClick="clearLog();"/>
</body>
</html>
KeyFrameTestBottom.asp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
</head>
<body>
<p>Press Keys Here</p>
<input type="Button" value="Reset Handlers"
onclick="top.frames.TOP.setKeyHook();">
</body>
</html>
To recreate the issue, right click the bottom frame, click refresh, click "Reset Hooks", and press keys.
Related Question: Handle keyPress Accross Frames in IE
I've also read an article on Javascript closures, but I'm not sure how it applies.
Sorry for the narrowness of question, but I really don't know Javascript well enough to figure out the trick to this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个放弃处理事件的“旧方法”的解决方案,而是使用更灵活和更强大的“事件侦听器”模型。 这允许传递事件对象
请注意,attachEvent() 方法仅适用于 IE(您在上一篇文章中规定这是可以的 - 但如果您支持其他内容,则需要更改此设置)
当以这种方式注册事件侦听器时,正确的事件对象会自动作为参数传递给处理函数。
Here's a solution that ditches the "old way" of handling events, and instead uses the more flexible and powerful "event listener" model. This allows the passing of event objects
Note that the attachEvent() method is IE only (which you stipulated as being ok in your previous post - but you'll need to change this if you support something else)
When event listeners are registered this way, the proper event object is automatically passed as an argument to the handler function.
当引用window时,它会解析调用范围的window对象,而不是驻留范围。
这意味着当您通过从底部框架执行 setKeyHook() 重新附加事件侦听器时,对 window 的引用与 top.frames.BOTTOM 相同,这不是您想要使用的窗口 - 您想要来自顶部窗口的事件 - 这将模仿此功能的初始使用。
因此,您应该能够通过使用对顶部框架中的事件的显式引用来解决此问题
When a reference to window is made, it resolves the the window object of the calling scope, not the residing scope.
What this means is when you re-attach the event listeners by executing setKeyHook() from the bottom frame, the reference to window is the same as top.frames.BOTTOM, which is not the window you want to use - you want the event from the TOP window - which would mimic the initial use of this function.
So, you should be able to fix this by using an explicit reference to the event in the TOP frame