【问题标题】:Finding a javascript "this" keyword substitute for Internet Explorer查找 javascript“this”关键字替代 Internet Explorer
【发布时间】:2023-03-25 15:50:01
【问题描述】:

我一直在开发一个基本的 javascript 下拉菜单,使用 addEventListener 和 attachEvent 来处理点击和鼠标功能。点击事件调用的函数subOpen,使用javascript“this”关键字获取被点击元素的id。

添加事件示例:

//add event listeners to menuitems
for (var i=0; i < menuitems.length; i++) {
    if (menuitems[i].addEventListener) {
        menuitems[i].addEventListener('click', subOpen, false);    
        menuitems[i].addEventListener('mouseout', closeTimer, false);
        menuitems[i].addEventListener('mouseover', cancelTimer, false);
        menuitems[i].addEventListener('selectstart', menucursorselect, false);
    } else if (menuitems[i].attachEvent) {
        menuitems[i].attachEvent('onclick', subOpen);    
        menuitems[i].attachEvent('onmouseout', closeTimer);
        menuitems[i].attachEvent('onmouseover', cancelTimer);
        menuitems[i].attachEvent('onselectstart', menucursorselect);    
    }
}

使用“this”关键字的 subOpen 函数示例:

function subOpen() {
cancelTimer(); //stops the close timer  

if (submenudisplay) {
    document.getElementById(submenudisplay).style.display = "none";
    activeSubMenu = false;
}
var curMenuId = this.id;
var curSubMenuId = this.id + "submenu";

if (curSubMenuId) {
    document.getElementById(curSubMenuId).style.display = "block";
    activeSubMenu = true;   
}

submenudisplay = curSubMenuId;

现在,除了早期版本的 Internet Explorer 之外,我测试过的所有浏览器都可以正常运行。对于旧版本的 IE,调试器会将“this.id”标记为未定义,因此它不知道要打开哪个子菜单。我做了一些研究,发现旧的IE在附加事件时不会复制函数,而是引用它,所以我无法使用“this”关键字捕获任何有用的数据。

我想知道是否有不同的关键字或函数可以用来完成与旧版本 IE 相同的工作。

我的完整版测试代码可以在here找到:

【问题讨论】:

  • 我讨厌推荐可怕的大框架,但这是 jQuery 擅长做的事情。它真的很方便,而且对 Internet Explorer 的处理也足够好。
  • 我会将 jQuery 描述为 温暖和模糊,而不是 又大又可怕。在这个时代,使用 JavaScript 时几乎可以理解为使用 jQuery。
  • @user1689607 - 哪一部分是废话? “温暖而模糊”还是“明白用过”?我认为第一个陈述非常可靠。第二个无疑是有问题的......
  • 抱歉,主要是后者,虽然我真的不认为 jQuery 大而可怕或温暖而模糊。这对我来说只是另一个代码库。

标签: javascript html


【解决方案1】:

您可以使用调用您的处理程序并手动设置this 值的函数。

在这里,我创建了一个bindHandler 函数,该函数接收元素和处理程序,并返回一个新处理程序,该处理程序以this 值作为元素调用原始处理程序。

它还将window.event 对象传递给原始处理程序以获得一致性。

for (var i=0; i < menuitems.length; i++) {
    if (menuitems[i].addEventListener) {
        menuitems[i].addEventListener('click', subOpen, false); 
        menuitems[i].addEventListener('mouseout', closeTimer, false);
        menuitems[i].addEventListener('mouseover', cancelTimer, false);
        menuitems[i].addEventListener('selectstart', menucursorselect, false);
    } else if (menuitems[i].attachEvent) {
        menuitems[i].attachEvent('onclick', bindHandler(menuitems[i], subOpen));   
        menuitems[i].attachEvent('onmouseout', bindHandler(menuitems[i], closeTimer));
        menuitems[i].attachEvent('onmouseover', bindHandler(menuitems[i], cancelTimer));
        menuitems[i].attachEvent('onselectstart', bindHandler(menuitems[i], menucursorselect));  
    }
}

function bindHandler(elem, handler) {
    return function() {
        return handler.call(elem, window.event);
    };
}

FWIW,我会创建一个单独的绑定函数来为你处理这个问题,以减少一些重复的代码。

for (var i=0; i < menuitems.length; i++) {
    bindHandler(menuitems[i], 'click', subOpen);
    bindHandler(menuitems[i], 'mouseout', closeTimer);
    bindHandler(menuitems[i], 'mouseover', cancelTimer);
    bindHandler(menuitems[i], 'selectstart', menucursorselect);
}

function bindHandler(elem, type, handler) {
    if (elem.addEventListener)
        elem.addEventListener(type, handler, false);
    else if (elem.attachEvent)
        elem.attachEvent("on" + type,  function() {
            return handler.call(elem, window.event);
        };
}

【讨论】:

    【解决方案2】:

    您应该使用 jQuery 来绑定事件,而不是直接调用 addEventListenerattachEvents 函数。 jQuery 将解决这些跨浏览器兼容性问题。

    所以我在这里的回答是不要这样做。但如果你这样做,请知道 Internet Explorer 调用的函数默认没有 this 关键字。为了访问该元素,您必须在window.event.srcElement 中查找该元素。在兼容 W3C 的浏览器上,您可以使用 thisevent.target。您可以使用下面的函数_addEventListener 作为W3C 函数的跨浏览器版本。

    var _addEventListener = function (obj, evt, ofnc, bubble) {
        var fnc = function (event) {
            if (!event || !event.target) {
                event = window.event;
                event.target = event.srcElement;
            }
            return ofnc.call(obj, event);
        };
        // W3C model
        if (obj.addEventListener) {
            obj.addEventListener(evt, ofnc, !!bubble);
            return true;
        }
        // M$ft model
        else {
            return obj.attachEvent('on' + evt, fnc);
        }
    };
    

    //add event listeners to menuitems
    for (var i = 0; i < menuitems.length; i++) {
        _addEventListener(menuitems[i], 'click', subOpen, false);
        _addEventListener(menuitems[i], 'mouseout', closeTimer, false);
        _addEventListener(menuitems[i], 'mouseover', cancelTimer, false);
        _addEventListener(menuitems[i], 'selectstart', menucursorselect, false);
    }​
    

    【讨论】:

    • @jahroy:根本不是。这个答案看起来像是从互联网上的其他地方抄袭而来的。我可以找到相同的代码示例,一直到 // M$ft model 代码注释。
    • @user1689607 它实际上是从我自己的一段代码中复制和简化的。原创here.
    • 很公平。我对指控表示歉意。但是我可以问一下为什么你将fnc传递给addEventListener而不是ofnc?如果支持addEventListener,则似乎没有必要修复事件对象。
    • 这实际上是一个很好的反馈。一年多前我写了这个函数,从来没想过。谢谢@user1689607
    • 在这种情况下,您可能还希望将处理程序包装函数移动到else,这样您就不会不必要地创建函数。无论如何,现代实现可能会对其进行优化,但以防万一......
    【解决方案3】:
    function addHandler(elem, type, handler) {
        elem.addEventListener(type, handler, false);
    }
    if (!document.addEventListener)
        addHandler = function(elem, type, handler) {
            elem.attachEvent('on'+type, function() {
                handler.call(elem, window.event);
            });
        };
    

    然后使用

    for (var i=0; i<menuitems.length; i++) {
        addHandler(menuitems[i], 'click', subOpen);
        addHandler(menuitems[i], 'mouseout', closeTimer);
        addHandler(menuitems[i], 'mouseover', cancelTimer);
        addHandler(menuitems[i], 'selectstart', menucursorselect);
    }
    

    【讨论】:

      【解决方案4】:

      实际的“事件”被传递给处理函数,你可以从事件中获取元素。

      http://www.javascripter.net/faq/eventtargetsrcelement.htm

      【讨论】:

      • srcElement 不一定与所需的 this 值相同。
      • 同意。我并不是说 srcElement 可以直接替换它。它足以解决手头的问题。
      猜你喜欢
      • 2015-09-04
      • 2018-02-01
      • 2010-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-17
      • 2010-12-14
      相关资源
      最近更新 更多