JavaScript学习笔记:浏览器事件

概念

客户端JavaScript程序使用异步事件驱动的编程模型。
浏览器会在文档、浏览器或某些元素或与之关联的对象发生某些事情时生成事件对象。比如文档加载完成、敲击键盘输入等。
JavaScript程序可以给某些对象绑定监听器函数来监听特定的事件,在该对象上发生指定事件时,这些函数会被执行。

在浏览器,事件可以发生在DOM元素对象、Window对象与Document对象等对象上面。
基于事件的编程有以下概念:

  • 事件类型: 一个字符串,表示发生了什么事。
  • 事件目标: 一个对象,表示事件发生的位置。
  • 事件监听器: 也叫事件处理程序,用于响应或处理事件
  • 事件对象:与特定事件关联的对象,包含该事件的细节。如type与target属性表示事件的类型与事件目标。
  • 事件传播: 是一个过程。有“捕获”与“冒泡”两种方式和"捕获","目标","冒泡"三个阶段。

事件类型

浏览器事件太多太多了,但是可以按照其共性分为几个类别:

  • 设备相关的输入事件:
    与如键盘、鼠标、触屏等特定设备相关的输入事件。如keydown,mouseup,touchdown等
  • 设备无关的输入事件:
    可由多种设备触发的事件,与某一特定设备无关。如click由鼠标或触屏触发,input可以由鼠标、键盘与触屏触发。
  • 用户界面事件:
    UI事件是高级事件,一般有表单元素触发。如focus由输入元素获得焦点时触发,change在输入元素的输入内容改变是触发,submit在表单提交时触发。
  • 状态变化事件:
    不由用户的主动行为触发,而是由网络或浏览器的活动触发。比如文档加载完毕时,触发Document对象的DOMContentLoaded;网络状态变化时触发Window对象的online与offline。
  • API特定事件:
    HTML及其相关规范定义的WebAPI包含了自己的事件,比如<video>与<audio>标签有waiting,playing,seeking等事件。XMLHttpRequest与IndexdDB都有自己的事件。

事件传播

两种方式:

  • 捕获:从Window对象开始到Document对象,再沿DOM树从上到下,直到目标元素。
  • 冒泡:与捕获相反,从目标对象开始向上传播,指到Window对象。

三个阶段:

  • 捕获阶段: 事件从Window对象开始向下传播,直到目标元素的父元素上,过程中的对象上注册为捕获事件监听器的监听器被触发。该阶段目标对象的监听器不会触发。
  • 目标阶段: 事件传播到目标元素,开始执行事件监听器,此阶段不分监听器的类型是捕获还是冒泡,按照它们的注册顺序执行。
  • 冒泡阶段: 目标元素执行完自身的处理程序后,事件开始向上传播,过程中的对象上注册为冒泡事件监听器的监听器被触发。

注册事件监听器

有三种形式:

  1. 作为对象的特定属性
element.onclick = function(event) {};
  1. 作为HTML标签的属性
<!-- 使用js代码 -->
<button onclick="console.log(1)">Click</button>
<!-- 使用js方法名,该方法需要在js代码中有定义 -->
<button onclick="clickHandler">Click</button>
  1. 使用EventTarget.addEventListener()方法
    上面的方法只能注册一个事件处理程序,而addEventListener()方法能注册多个监听器。
    它接收三个参数:
  • type: 字符串,表示事件类型
  • listener: 一个实现了 EventListener 接口的对象,或者是一个函数。
  • useCapture / options: 可选的一个布尔值或对象。
    • 布尔值: 是否注册为捕获事件监听器,默认为冒泡事件监听器
    • 对象: 有以下可选的字段:
      • capture: 布尔类型。为true将函数注册为捕获事件监听器,未指定该字段或false为冒泡事件监听器
      • once: 布尔类型。为 true,listener 会在其被调用一次之后自动移除。
      • passive: 布尔类型。为 true,表示 listener 永远不会调用 preventDefault()来取消事件的默认行为。若仍然调用该方法,会在控制台抛出警告。

监听器函数接收一个Event对象作为唯一的参数。

let btn = document.querySelector('button');
btn.addEventListener('click', function(event) {}, false);
btn.addEventListener('click', function(event) {}, {capture: true});

取消事件与阻止事件传播

Event接口的preventDefault()方法可以取消事件的默认行为,比如阻止输入元素输出内容。但对于passive为true的事件,该方法不能起作用。

Event 接口的 stopPropagation() 方法阻止捕获和冒泡阶段中当前事件的进一步传播,但是它不能取消事件的默认行为,也不能阻止同一元素上与该事件相关的其他监听器的触发。
Event 接口的 stopImmediatePropagation() 方法除了阻止事件的继续传播,还阻止监听同一事件的其他事件监听器被调用。

事件监听器的上下文

作为事件监听器的函数,若以function关键字定义,则其this值指向注册监听器的目标对象;
若以箭头函数定义,其this值则指向函数被定义时其作用域的this值。

监听器的返回值

监听器不应该有返回值。
虽然返回false,可以告诉浏览器取消事件的默认行为,但是标准的做法是使用preventDefault()方法。

事件对象

事件对象有以下几个常用的属性:

  • type: 字符串,事件类型。
  • target: 事件发生的对象
  • currentTarget: 注册事件监听器的对象
  • timeStamp: 事件发生时间的毫秒级时间戳
  • isTrusted: 表示事件是由浏览器(例如用户点击)发起的;false表示由脚本(使用事件创建方法,例如 Event.initEvent)发出的。
  • 更多属性: Event#属性

自定义事件

使用EventTarget接口 的 dispatchEvent() 方法将一个自定义事件派发给目标对象。
自定义事件对象可由CustomEvent()构造函数创建。
CustomEvent()构造函数接收的第一个参数是一个表示事件类型的字符串,第二个参数是一个描述事件的对象。
该对象有以下可选的字段:

  • detail: 任意类型的值,默认为null,表示事件的上下文。
  • bubble: 为true表示事件可以冒泡。默认情况下事件只能捕获。
  • cancelable: 布尔值,表示事件是否能被取消。

也可以由document.crateEvent('Event')创建,并由initEvent()方法初始化。

<html>
    <head></head>
    <body>
        <button>Click</button>
    </body>

    <script type="text/javascript">
        let btn = document.querySelector('button'),
            handler = function(event) {
            console.log(event.type, event.target, event.currentTarget);
        };
        let event = new Event("look", {"bubbles":true, "cancelable":false});
        let ev = document.createEvent('Event');
        // 事件类型,是否冒泡,是否可以取消
        ev.initEvent('see', true, false);
        // 注册监听器
        btn.addEventListener('look', handler, false);

        btn.onclick = () => {
            // 派发事件
            btn.dispatchEvent(event);
        };
    </script>
</html>
posted @ 2023-06-03 13:09  钰琪  阅读(73)  评论(0编辑  收藏  举报