2

我一直在研究一个基本的 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 相同的事情。

我的测试代码的完整版本可以在这里找到:

4

4 回答 4

4

您可以使用调用处理程序并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);
        };
}
于 2012-10-25T17:22:40.537 回答
1
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);
}
于 2012-10-25T17:31:46.297 回答
1

您应该使用 jQuery 来绑定事件,而不是直接调用addEventListenerandattachEvents函数。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);
}​
于 2012-10-25T17:33:01.787 回答
-1

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

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

于 2012-10-25T17:25:21.650 回答