Sky
HOME
HOME
  • 前端笔记

    • CSS

      • 盒子模型
      • 屏幕单位
      • CSS 性能优化
    • JavaScript

      • Methods

        • Scheduler
        • Deep Clone
        • Curry
        • Calculation Function
        • debounce & throttle
      • Function bind
      • Array reduce
      • cross domain
      • event loop
      • ajax
      • event
      • context
      • inheritance
      • prototype
    • HTML

      • html render
      • forbidden <a>
      • <meta>
      • <script>
    • uni-app

      • scroll table

event | 事件

事件 & 事件流

事件是可以被 JavaScript 侦测到的行为。

鼠标点击、鼠标移动、鼠标滚动、按下键盘,浏览器窗口大小的改变,网页加载完成,关闭网页等等都会发生事件。

事件流有两种:

  • 事件冒泡
    IE的事件流叫事件冒泡,即事件开始时由最具体的元素(文档中嵌套层次最深的节点)接收,然后逐级向上传播到较为不具体的节点。
  • 事件捕获
    Netscape团队提出的另一种事件流叫事件捕获,事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。

一个DOM事件分为三个阶段

  • 事件捕获阶段(capture phase)
  • 处于目标阶段(target phase)
  • 事件冒泡阶段(bubble phase)

flow of event

事件捕获阶段为事件的触发奠定了基础,当DOM事件发生的时候,首先由最不具体的 window 结点向下捕获那个具象元素(触发事件的元素),事件捕获之后就开始执行绑定在上面的函数;当函数执行完毕,触发事件冒泡进入冒泡阶段,一直从触发的元素逐级想上传递,直至 window 元素。

事件模型

  • 原始事件模型(DOM0级)
  • 标准事件模型(DOM2级)
  • IE事件模型

原始事件模型(DOM0级)

  1. HTML 代码中直接绑定

        <button onclick="alert('click')">click</button>
    
  2. 通过 JavaScript 代码绑定

        var btn = document.getElementById('btn');
        btn.onclick = function() {
            alert('click');
        }
    
  3. 移除事件

        var btn = document.getElementById('btn');
        btn.onclick = null;
    
  4. 特性

    • 绑定速度快

      DOM0 级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行

    • 只能绑定一个事件处理函数

      当希望为同一个元素绑定多个同类型事件的时候,后面的事件会覆盖前面的事件

    • 只支持冒泡,不支持捕获

标准事件模型(DOM2级)

三个过程:

  1. 事件捕获阶段
    从document一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
  2. 处于目标阶段
    到达目标元素, 触发目标元素的监听函数
  3. 事件冒泡阶段 从目标元素冒泡到 document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行

两个方法:
1 . addEventListener -> 添加事件侦听器
2 . removeEventListener -> 移除事件侦听器

    /**
     * @param {String} eventType 指定事件类型(不要加on -> 'click')
     * @param {Function} handler 事件处理函数
     * @param {Boolean} useCapture 是否在捕获阶段触发事件处理函数,一般设置为false与IE浏览器保持一致
     * 
     * */ 
    var btn = document.getElementById('.btn');
    // 添加事件侦听器
    btn.addEventListener(eventType, handler, useCapture);
    // 移除事件侦听器
    btn.removeEventListener(eventType, handler, useCapture);

特性:

  • 可以绑定多个事件处理函数
  • 当第三个参数(useCapture)设置为true就在捕获过程中执行,反之在冒泡过程中执行处理函数
  • 事件处理函数的 this 指向触发事件的元素

IE事件模型

两个过程:

  1. 事件处理阶段
    到达目标元素, 触发目标元素的监听函数。
  2. 事件冒泡阶段
    从目标元素冒泡到 document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。

两个方法:

  1. attachEvent -> 绑定监听函数
  2. detachEvent -> 移除监听函数
    /**
     * @param {String} eventType 指定事件类型(带on -> 'onclick')
     * @param {Function} handler 事件处理函数
     * 
     * */ 
    var btn = document.getElementById('.btn');
    // 添加事件侦听器
    btn.attachEvent(eventType, handler);
    // 移除事件侦听器
    btn.detachEvent(eventType, handler);

事件代理(Event delegation)

事件代理也叫事件委托,是指将事件绑定到目标元素的父元素上,然后通过事件冒泡机制触发该事件。

<div id="box">
    <input type="button" value="按钮" id="btn">
    <input type="button" value="按钮2" id="btn2">
    <input type="button" value="按钮3" id="btn3">
</div>

<script>
    // 直接通过父节点一次性为所有子结点注册监听函数:
    var box = document.getElementById('box');
    box.onclick = function(e) {
        var e = e || window.event;
        var target = e.target || e.srcElement;
        if (target.nodeName.toLowerCase() === 'input') {
            alert(target.value);
        }
    }
    // target 返回触发事件的元素,不一定是绑定事件的元素
    // currentTarget 返回的是绑定事件的元素
</script>

优点:

  • 减少内存消耗,提高性能

    每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。

  • 动态监听事件

    当新增子元素时,无需再次为新增元素绑定事件,因为事件是绑定在父元素上的,所以新增元素也会有相同的事件。

阻止冒泡/默认行为

    // 阻止事件冒泡
    function stopPropagation(e) {
        e = e || window.event;
        if(e.stopPropagation) {
            e.stopPropagation(); //W3C阻止冒泡方法
        } else {
            e.cancelBubble = true; //IE阻止冒泡方法
        }
    }

    // 阻止默认行为
    function preventDefault(e) {
        e = e || window.event;
        if(e.preventDefault) {
            e.preventDefault(); //W3C阻止默认行为
        } else {
            e.returnValue = false; //IE阻止默认行为
        }
    }

    child.onclick = function (e) {
        alert("你点击了child区域");
        stopPropagation(e);
        preventDefault(e);
    };
    
最近更新: 2023/8/30 17:38
Contributors: liujw155@outlook.com
Prev
ajax
Next
context