乐趣区

详解JS事件-事件模型事件流事件代理事件对象自定义事件

事件模型

  • DOM0 级事件模型 - 没有事件流,这种方式兼容所有浏览器

    // 方式一  将事件直接通过属性绑定在元素上
    <button onclick="clickBtn()"></button>
    / 方式二 获取到页面元素后,通过 onclick 等事件,将触发的方法指定为元素的事件
    var btn = document.getElementById('btn')
    btn.onclick = function () {...}
    btn.onclick = null
  • IE 事件模型 – 只有冒牌,仅在 IE 浏览器中有效,不兼容其他浏览器

    1. 事件处理阶段:事件在达到目标元素时,触发监听事件
    2. 事件冒泡阶段:事件从目标元素冒泡到 document,并且一次检查各个节点是否绑定了监听函数,如果有则执行
    // 绑定事件
    el.attachEvent(eventType, handler)
    // 移除事件
    el.detachEvent(eventType, handler)
  • DOM2 级事件模型 – W3C 标准模型,除 IE6-8 以外的所有现代浏览器都支持该事件模型

    1. 事件捕获阶段:事件从 document 向下传播到目标元素,依次检查所有节点是否绑定了监听事件,如果有则执行 – 从外向内,把这个坐标转换为具体的元素上事件的过程,就是捕获过程 (点击事件来自触摸屏或者鼠标,鼠标点击并没有位置信息,但是一般操作系统会根据位移的累积计算出来,跟触摸屏一样,提供坐标给浏览器)
    2. 事件处理阶段:事件在达到目标元素时,触发监听事件
    3. 事件冒泡阶段:事件从目标元素冒泡到 document,并且一次检查各个节点是否绑定了监听函数,如果有则执行 – 从内向外,是人类处理事件的逻辑
    // 绑定事件
    target.addEventListener(type, listener[, useCapture]);
    // 移除事件
    target.addEventListener(type, listener[, useCapture]);

事件流:

  • 浏览器事件流向捕获阶段、目标阶段、冒泡阶段,就是我们所说的 - W3C 事件模型
  • 兼容的事件绑定写法

    function bindEvent(obj, type, fn) {if (obj.addEventListener) {obj.addEventListener(type, eventFn);
        } else {obj.attachEvent("on" + type, eventFn);
        }
        function eventFn(ev) {
          var ev = ev || window.event;
          var target = ev.target || ev.srcElement;
          fn && fn(target, ev)
        }
      }

事件代理

  • 定义:指利用“事件冒泡”,只通过指定一个事件处理程序,来管理某一类型的所有事件
  • 优点:

    (1)可以大量节省内存占用,减少事件注册,比如在 table 上代理所有 td 的 click 事件就非常棒

    (2)可以实现当新增子对象时无需再次对其绑定事件,对于动态内容部分尤为合适

  • 缺点:仅限于上述需求下,如果把所有事件都用代理就可能会出现事件误判,即本不应用触发事件的被绑上了事件
  • demo: 把动态列表的点击事件,绑定在父元素上

事件对象 Event

元素进行事件监听的时候,它的回调函数里就会默认传递一个参数 event,它是一个对象

  • 属性:

    • event.target:指的是触发事件的那个节点,也就是事件最初发生的节点 (fn 触发的元素)
    • event.currentTarget:指的是正在执行的监听函数的那个节点 (fn 绑定的元素)
    • event.isTrusted:表示事件是否是真实用户触发。
    • event.preventDefault():取消事件的默认行为。
    • event.stopPropagation():阻止事件的派发(包括了捕获和冒泡)
    • event.stopImmediatePropagation():阻止同一个事件的其他监听函数被调用。
  • target 和 currentTarget 区别:触发事件的元素和事件绑定的元素
  • stopPropagation 和 stopImmediatePropagation 区别:

    • stopPropagation 只对书写的那个事件有用,再绑定另一个 click 失效
    • stopImmediatePropagation 对绑定的很多类型的事件都有用
  • 兼容写法:ev.target || ev.srcElement

addEventListener(W3C)

  • 参数:

    • 事件名称 event
    • 事件处理函数 / 具有 handleEvent 函数的对象 listener
    • 第三个参数

      • once:只执行一次
      • passive:承诺此事件监听不会调用 preventDefault,这有助于性能
      • useCapture:是否捕获 true(否则冒泡 false)
  • 移除:removeEventListener(事件名称、事件回调、捕获 / 冒泡)

自定义事件:

只能在 DOM 元素上自定义事件

// 使用 Event 构造器来创造了一个新的事件
var evt = new Event("look", {"bubbles":true, "cancelable":false});
document.dispatchEvent(evt);

面试题

  • 了解 js 的事件吗?
  • 说说 js 的事件 / 绑定事件的方法?/ 了解事件流吗?
  • 事件流的顺序是什么?

补充

  • React 组件中怎么做事件代理
  • React 组件事件代理的原理
  • React 的事件合成机制好像和 js 的不太一样(绑定一个事件到一个组件上)
  • Emit 事件怎么发,需要引入什么
  • 页面上生成一万个 button,并且绑定事件,如何做(JS 原生操作 DOM)
  • 添加原生事件不移除为什么会内存泄露
  • vue 中的 native 修饰符
  • 移动端点击穿透:fastclick
  • 手写原生 js 实现事件代理,并要求兼容浏览器
  • 事件如何派发也就是事件广播(dispatchEvent
  • 总结:https://www.cnblogs.com/dfyg-…
  • 手写一个冒泡排序处理事务
退出移动版