zoukankan      html  css  js  c++  java
  • JavaScript中事件处理

    先看看下面一道题目,请评价以下代码并给出改进意见:

    if (window.addEventListener) {//标准浏览器
      var addListener = function(el, type, listener, useCapture) {
        el.addEventListener(type, listener, useCapture);
      };
    } else if (document.all) {//IE
      addListener = function(el, type, listener) {
        el.attachEvent("on" + type, function() {
          listener.apply(el);
        });
      }
    }

    1)不应该在if和else语句中声明addListener函数,应该先声明;

    2)不需要使用window.addEventListener或document.all来进行检测浏览器,应该使用能力检测;

    3)attachEvent在IE中有this指向问题,会指向window,虽然上面的代码做了指向处理,但是匿名函数不能做detachEvent解绑

    改进后的代码稍后加上。

    一、冒泡与捕获

    使用过addEventListener方法的会发现最后一个参数“useCapture”,用于控制是捕获还是冒泡。

    何为冒泡、捕获,请看下面的例子:查看在线代码,在线代码中用了三层。

    <div id="click1">
      <div id="click2">事件</div>
    </div>

    1)Netscape主张元素1的事件首先发生,这种事件发生顺序被称为捕获型,如下图所示:

                   | |
    ---------------| |-----------------
    | click1       | |                |
    |   -----------| |-----------     |
    |   |click2     /          |     |
    |   -------------------------     |
    |        Event CAPTURING          |
    -----------------------------------

    2)微软则保持元素2具有优先权,这种事件顺序被称为冒泡型,如下图所示:

                   / 
    ---------------| |-----------------
    | click1       | |                |
    |   -----------| |-----------     |
    |   |click2    | |          |     |
    |   -------------------------     |
    |        Event BUBBLING           |
    -----------------------------------

    3)W3C选择了一个择中的方案。任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段,如下图所示:

                   | |  / 
    ---------------| |--| |------------
    | click1       | |  | |           |
    |   -----------| |--| |------     |
    |   |click2     /  | |     |     |
    |   -------------------------     |
    |      W3C event model            |
    -----------------------------------

    4)阻止冒泡,很多时候是不想触发父级的相同事件的,那么就需要阻止这种行为。

    W3C方:event.stopPropagation()。(chrome、firefox、safrai等)

    IE方:event.cancelBubble设置为true。

    经过我的在线测试,stopPropagation这个方法不能阻止捕获。

    这里顺带说下阻止默认事件的方法,何为默认事件?就比如a标签设置了href,就会做跳转,这里阻止它跳转。

    W3C方:event.preventDefault(),但只有event的cancelable属性为true时才能使用。

    IE方:event.returnValue设置为false。

     

    二、事件系统

    浏览器提供了3种层次的API。

    1)最原始的是写在元素标签内

    2)以el.onXXX=function绑定的方式,通称为DOM0事件系统。

    3)一个元素的同一类型事件可以绑定多个回调,通称为DOM2事件系统。

    IE与W3C依旧不同,语法如下:

    序号  操作与对象 IE方 W3C方

    1

    绑定事件

    el.attachEvent("on"+type, callback) el.addEventListener(type,callback,[useCapture])

    2

    卸载事件

    el.detachEvent("on"+type,callback) el.removeEventListener(type,callback,[useCapture])
    3 创建事件 document.createEventObject()

    document.createEvent(types) 创建事件(过时

    event.initEvent() 初始化事件(过时

    new Event(types)

    4

    派发事件

    el.fireEvent(type,event) el.dispatchEvent(event)
    5 event属性 srcElement:等于target,默认目标

    currentTarget:其事件处理程序当前正处理事件的元素

    target:事件的目标

    6 event方法

    returnValue:等于preventDefault()

    cancelBubble:设为true等于stopPropagation()

    preventDefault():阻止默认行为

    stopPropagation():阻止冒泡

    7

    type

    被触发的事件类型,需要“on”前缀 被触发的事件类型

    8

    事件执行顺序

    与添加顺序相反 与添加顺序一致
    9

    匿名函数

    无法移除 无法移除

    10

    this

    window 当前绑定的元素

    注意第8点,在测试代码中,我绑定了两个相同的“click”事件, 查看在线完整代码

    var func1 = function(e) {
      alert(1); //测试执行顺序
    };
    var func2 = function(e) {
      alert(2);
    };
    var type = 'click';
    bind(ele, type, func1);
    bind(ele, type, func2);

    在IE中先弹出2,再弹出1。而在chrome中先弹出1,再弹出2。

    注意上面的第9点和第10点,上面那道题目中要解决的就是这个问题。下面的代码是个片段,查看在线完整代码

    var bind = function(ele, type, callback) {
      if (!ele[type + "event"]) {
        ele[type + "event"] = {}; //声明一个空对象,缓存事件
      }
      var name = callback.toString();
      if (!ele[type + "event"][name]) {
        var handler = function(event) {
          //可以做更多event封装操作
          var ev = event || window.event;
          callback.call(ele, ev);
        };
        ele[type + "event"][name] = handler; //做个临时变量
      }
    
      if (ele.addEventListener) {
        ele.addEventListener(type, handler, false);
      } else if (ele.attachEvent) {
        ele.attachEvent('on' + type, handler);
      }
    }
    var unbind = function(ele, type, callback) {
      var handler = ele[type + "event"][callback.toString()]; //读取临时变量
      if (ele.removeEventListener) {
        ele.removeEventListener(type, handler);
      } else if (ele.detachEvent) {
        ele.detachEvent('on' + type, handler);
      }
    }

    上面的代码还比较粗糙,仅仅是用于演示一下。方法有很多,自己可以揣摩。

    我看到网上有人直接不用attachEvent,将相应的事件保存在一个数组中,当detachEvent的时候做splice数组的操作。

    大家也可以参考下一些成熟的类库,例如jQuery1.8.3版本,2642行的event.add封装,2757行的event.remove封装,3485行的on封装。

    也可以参考Dean Wdwards写的addEvent方法,这是Prototype时代早期出现的一个事件系统,jQuery事件系统的源头。

    参考资料:

    前端事件系统(一)

    JavaScript要点归档:事件

    生动详细解释javascript的冒泡和捕获

    解决attachEvent中this指向问题

    创建和触发 events

  • 相关阅读:
    C++派生类中定义基类的虚函数时需注意的事项
    [wp7软件]wp7~~各种视频播放器下载大全! 集合贴~~~
    [wp7软件]wp7~~日历软件下载大全! 集合贴~~~
    [wp7软件]相机 画图 截屏 photo 集合 软件(三)
    [wp7软件]相机 画图 截屏 photo 集合 软件(二)
    [wp7软件]wp7~~天气查询软件下载大全! 集合贴~~~
    [wp7软件]相机 画图 截屏 photo 集合 软件(一)
    [wp7软件]wp7~~各种浏览器下载大全! 集合贴~~~
    [wp7软件]wp7~~各种音乐播放器下载大全! 集合贴~~~
    [wp7软件]相机 画图 截屏 photo 集合 软件(四)
  • 原文地址:https://www.cnblogs.com/strick/p/5004921.html
Copyright © 2011-2022 走看看