• DOM 中的事件处理


    根据 W3C DOM 2 Events 描述,EventTarget 接口被所有支持 DOM 事件模型的节点(Node)实现。 该接口提供了 'addEventListener' 和 'removeEventListener' 方法,用来绑定或解绑一个 EventListeners 接口到一个 EventTarget。

    DOM 2 Events 中定义了 Event 接口,用来提供事件的上下文信息,它提供了若干标准属性和方法。 实现 Event 接口的对象一般作为第一个参数传入事件处理函数,以用来提供当前事件相关的一些信息。

    事件注册

    根据 DOM 2 Events 中描述,节点使用 'addEventListener' 和 'removeEventListener' 方法绑定和解绑事件监听器,但 IE6 IE7 IE8 不支持这两个方法, 而使用 'attachEvent' 和 'detachEvent' 方法作为替代方案,Opera 两类方法都支持。Chrome Safari Firefox 只支持标准方法。

    为了解决浏览器兼容问题,可以自定义函数来解决。例如:

    var EventUtil = {
    addHandler: function (element, type, handler) {
    if (element.addEventListener) {
    element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
    element.attachEvent("on" + type, handler);
    } else {
    element["on" + type] = handler;
    }
    },
    removeHandler: function (element, type, handler) {
    if (element.removeEventListener) {
    element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
    element.detachEvent("on" + type, handler);
    } else {
    element["on" + type] = null;
    }
    }
    };

    关于 'addEventListener' 和 'attachEvent' 有几点需要注意:

    • IE 不支持在捕获阶段触发事件监听器,'attachEvent' 方法没有提供参数说明是否响应在捕获阶段触发的事件;
    • 'addEventListener' 和 'attachEvent' 都可以注册多个事件监听器;
    • 在 Firefox Chrome Safari Opera 中给同一事件注册同一个事件监听器多次,重复注册的会被丢弃;而在 IE 中重复注册的事件监听器会被重复执行多次;
    • 当给同一元素注册了多个事件监听器的时候,IE6 IE7 的事件监听器执行顺序是随机的,IE8 是倒序的,Firefox Chrome Safari Opera 是顺序的;
    • 当元素注册的事件监听器中有非法的事件监听器时(非函数),在 IE Firefox 中会抛出异常,而在 Chrome Safari Opera 中则会忽略非法的事件监听器,继续执行其他的事件监听器。

    事件对象

    在ie中,事件对象是作为一个全局变量来保存和维护的。 所有的浏览器事件,不管是用户触发的,还是其他事件, 都会更新window.event 对象。 所以在代码中,只要轻松调用 window.event 就可以轻松获取 事件对象, 再 event.srcElement 就可以取得触发事件的元素进行进一步处理。

    对于标准的 DOM 处理来说, 事件对象却不是全局对象,一般情况下,是现场发生,现场使用,把事件对象自动传递给对应的事件处理函数。 在代码中,函数的第一个参数就是事件对象了。

    为了解决兼容性问题,通常在代码中如下处理:

    function handler(e){
    e = e || window.event;
    }

    需要注意的是,使用 <button id="btn" onclick="foo()">按钮1</button> 进行事件注册,标准方式下却不能在事件处理方法中取得事件对象。

    原因是 onclick="foo()"   就是直接执行了, foo() 函数,没有任何参数传递给 foo 函数。

    有两个办法解决这个问题。

    第一,将注册的方法修改为 <button id="btn" onclick="foo(event)">按钮</button>,注意,这里的 event 不是形参,而是实参,必须名为 event。这样 foo 函数就可以得到事件参数了。

    第二,不修改注册的代码,在事件处理方法上进行处理。关键在于此时实际上存在事件对象,只不过没有传递给 foo 函数罢了,我们可以找到调用 foo 函数的那个函数,当然这是一个系统函数,没有关系,通过 foo.caller 可以取得当前调用 foo 函数的函数,这个函数的第一个参数就是事件对象,所以,我们可以这样取得这个事件对象了。foo.caller.arguments[0]

    注意:

    • 只有在使用 attachEvent 方法注册事件监听器的时候,IE 才支持使用事件监听器传入的第一个参数作为事件对象的方式;
    • Chrome Safari Opera 两种获取事件对象的方式都支持;
    • Firefox 只支持获取事件对象的标准方式。

    事件对象的属性

    IE 对事件对象的标准属性和方法支持有限,针对大部分属性和方法,IE 都提供了一套替代非标准的替代方案; 而 Firefox Chrome Safari Opera 除了全面支持事件对象的标准属性和方法外,还在不同程度上支持了 IE 提供的非标准替代方案。

    使用特性判断使用与标准对应的非标准方法及属性

      target          srcElement

      preventDefault()     returnValue

      stopPropagation()    cancelBubble

      relatedTarget      fromElement toElement

    例如:

    getEvent: function (event) {
    return event ? event : window.event;
    },
    getTarget: function (event) {
    return event.target || event.srcElement;
    },
    preventDefault: function (event) {
    if (event.preventDefault) {
    event.preventDefault();
    } else {
    event.returnValue = false;
    }
    },
    stopPropagation: function (event) {
    if (event.stopPropagation) {
    event.stopPropagation();
    } else {
    event.cancelBubble = true;
    }
    }


    参考资料:

    SD9011: 事件模型在各浏览器中存在差异





  • 相关阅读:
    Minecraft我的世界如何联机
    关于我的博客地址jvav的由来
    ThreadLocal使用
    使用免费tk域名
    MVC的request,response流程
    TiDB原理与集群架构
    net5 自定义 中间件
    net5 Autofac支持
    net5 Autofac 支持AOP (1)
    mysql 索引优化
  • 原文地址:https://www.cnblogs.com/haogj/p/2325073.html
Copyright © 2020-2023  润新知