调用跨框架时,Javascript 事件在闭包中未正确设置

发布于 2024-07-25 22:25:36 字数 7429 浏览 1 评论 0原文

我在两帧页面的顶部框架中有以下代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

这是一个放弃处理事件的“旧方法”的解决方案,而是使用更灵活和更强大的“事件侦听器”模型。 这允许传递事件对象

请注意,attachEvent() 方法仅适用于 IE(您在上一篇文章中规定这是可以的 - 但如果您支持其他内容,则需要更改此设置)

function setKeyHook()
{
  var botDocument = top.frames.BOTTOM.document;
  var topDocument = top.frames.TOP.document;
  var eventName = 'onkeydown';
  var handlerFunc = top.frames.TOP.handleKeypress;

  //    Clear them first, or else they'll attach twice and thusly, fire twice
  botDocument.detachEvent( eventName, handlerFunc );              
  topDocument.detachEvent( eventName, handlerFunc );

  topDocument.attachEvent( eventName, handlerFunc );
  botDocument.attachEvent( eventName, handlerFunc );
}

当以这种方式注册事件侦听器时,正确的事件对象会自动作为参数传递给处理函数。

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)

function setKeyHook()
{
  var botDocument = top.frames.BOTTOM.document;
  var topDocument = top.frames.TOP.document;
  var eventName = 'onkeydown';
  var handlerFunc = top.frames.TOP.handleKeypress;

  //    Clear them first, or else they'll attach twice and thusly, fire twice
  botDocument.detachEvent( eventName, handlerFunc );              
  topDocument.detachEvent( eventName, handlerFunc );

  topDocument.attachEvent( eventName, handlerFunc );
  botDocument.attachEvent( eventName, handlerFunc );
}

When event listeners are registered this way, the proper event object is automatically passed as an argument to the handler function.

○愚か者の日 2024-08-01 22:25:36

当引用window时,它会解析调用范围的window对象,而不是驻留范围。

这意味着当您通过从底部框架执行 setKeyHook() 重新附加事件侦听器时,对 window 的引用与 top.frames.BOTTOM 相同,这不是您想要使用的窗口 - 您想要来自顶部窗口的事件 - 这将模仿此功能的初始使用。

因此,您应该能够通过使用对顶部框架中的事件的显式引用来解决此问题

function setKeyHook()
{
    logMessage("setKeyHook()");
    top.frames.BOTTOM.document.onkeydown = 
    top.frames.TOP.document.onkeydown = function( evt )
    {
            return function(){
                top.frames.TOP.handleKeypress(evt);
            };

    }( top.frames.TOP.event ); // here
}

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

function setKeyHook()
{
    logMessage("setKeyHook()");
    top.frames.BOTTOM.document.onkeydown = 
    top.frames.TOP.document.onkeydown = function( evt )
    {
            return function(){
                top.frames.TOP.handleKeypress(evt);
            };

    }( top.frames.TOP.event ); // here
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文