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

标签 javascript internet-explorer dom-events html-frames

我在一个双框架页面的顶部框架中有以下代码:

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;

这适用于原始文档加载,但是当我从另一个框架调用此函数时(通常只有一个框架重新加载时),钩子(Hook)被设置,但是当 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>   

要重现问题,请右键单击底部框架,单击刷新,单击“重置 Hook ”,然后按键。

相关问题:Handle keyPress Accross Frames in IE

我还阅读了关于 Javascript closures 的文章,但我不确定它是如何应用的。

对于问题的狭隘性,我深表歉意,但我真的不太了解 Javascript,无法找出解决这个问题的诀窍。

最佳答案

这里有一个解决方案,它摒弃了处理事件的“旧方法”,而是使用更灵活、更强大的“事件监听器”模型。这允许传递事件对象

请注意,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 );
}

当事件监听器以这种方式注册时,适当的事件对象会自 Action 为参数传递给处理函数。

关于调用跨框架时未在闭包中正确设置 Javascript 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1059574/

相关文章:

javascript - 使用 jQuery 从 <select> 字段生成键值对

javascript - 在 IE 7/8 中使用 alt + shift + a 作为热键

javascript 选择选项功能在 IE 和 safari 中不起作用

javascript - D3js : mouseover of one element change opacity of several others elements

javascript - 悬停效果与 JavaScript

javascript - 使用样式将图像从用户计算机添加到 Canvas

javascript - 三个 js - 无法看到旋转的对象

javascript - window.print() 在 IE 11 中不起作用

javascript - 而鼠标按下事件。原型(prototype) JS 或 Javascript

JavaScript 递归搜索