JavaScript 教程 - part 3

1. 事件

1.1 EventTarget 接口

事件本质是程序各个组成部分之间的一种通信方式。DOM的事件触发都定义在EventTarget接口当中,所有节点对象都部署了这个接口

该接口主要提供了三个实例方法:

  • addEventListener 绑定事件的监听函数
  • removeEventListener 移除事件的监听函数
  • dispatchEvent 触发事件

1.1.1 EventTarget.addEventListener()

  • 用于在当前节点或对象上,定义一个特定的时间的监听函数,一旦这个事件发生,就会执行监听函数
  • 没有返回值
  • target.addEventListener(type, listener, [useCapture])
    • type 事件名称
    • listener 监听函数 事件发生,就调用这个监听函数
    • useCapture 表示监听函数是否在捕获阶段触发,默认为false (只在冒泡阶段被触发)
      • 捕获指的是事件从最外层开始发生,直到最具体的元素
      • 冒泡指从最内层开始发生
    • 第三个参数 – 是个属性配置对象,即除了useCapture 你还可以配置很多其他属性的
      • capture 是否在捕获阶段触发监听函数
      • once 是否只触发一次,然后就自动移除
      • passive 表示监听函数不会调用事件的preventDefault方法,如果监听函数调用了,浏览器就会忽略这个要求,并在监控台上输出一行警告
function hello() {
  console.log('Hello world');
}

var button = document.getElementById('btn');
button.addEventListener('click', hello, false);

1.1.2 EventTarget.removeEventListener()

用来移除addEventListener方法添加的事件监听函数,该方法没有返回值。

  • removeEnventListener方法移除的监听函数必须是addEventListener方法已经添加过得,而且必须在同一个元素节点上,否则无效

1.1.3 EventTarget.dispatchEvent()

  • 在当前节点触发指定事件,从而触发监听函数的执行 返回一个布尔值
  • 只要有一个监听函数调用了Event.preventDefault(),返回值为false,否则为true
para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);

1.2 事件模型

这一部分想要解决的问题是JS作为使用事件驱动编程模式(event-driven)的编程语言,是怎么样给事件绑定监听函数的。

1.2.1 绑定监听函数

1.2.1.1 使用html on属性

HTML允许在元素属性当中,直接定义某些事件的监听代码

<body onload="doSomething()">
  • 元素的监听属性,都是on加上事件名
  • 属性的值为将要执行的代码,单单函数名是不被允许的
  • 该种方式的监听代码,只会在冒泡阶段被触发
// 先输出1 再输出2
<div onClick="console.log(2)">
  <button onClick="console.log(1)">点击</button>
</div>

1.2.1.2 使用元素节点的事件属性

  • 也是只可以在冒泡阶段进行触发
window.onload = doSomething;

div.onclick = function (event) {
  console.log('触发事件');
};

1.2.1.3 使用addEventListener()

用来为该节点定义事件的监听函数

1.2.2 事件的传播

事件发生后,会在子元素和父元素之间进行传播,分为以下几个阶段:

  1. 从window对象传导到目标节点(上层传到底层),成为捕获阶段(capture phase)
  2. 在目标节点上触发,称为目标阶段
  3. 从目标节点传导会window对象,称为冒泡阶段 - bubbling phase

这种三阶段的传播模型,使得同一个事件会在多个节点上触发。

<div>
  <p>点击</p>
</div>

var phases = {
  1: 'capture',
  2: 'target',
  3: 'bubble'
};

var div = document.querySelector('div');
var p = document.querySelector('p');

div.addEventListener('click', callback, true);
p.addEventListener('click', callback, true);
div.addEventListener('click', callback, false);
p.addEventListener('click', callback, false);

function callback(event) {
  var tag = event.currentTarget.tagName;
  var phase = phases[event.eventPhase];
  console.log("Tag: '" + tag + "'. EventPhase: '" + phase + "'");
}

// 点击以后的结果
// Tag: 'DIV'. EventPhase: 'capture'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'DIV'. EventPhase: 'bubble'

1.2.3 事件的代理

因为事件会在冒泡阶段向上传播到父节点,因此可以将子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件的代理

var ul = document.querySelector('ul');

ul.addEventListener('click', function (event) {
  if (event.target.tagName.toLowerCase() === 'li') {
    // some code
  }
});

上面代码中,click事件的监听函数定义在<ul>节点,但是实际上,它处理的是子节点<li>的click事件。这样做的好处是,只要定义一个监听函数,就能处理多个子节点的事件,而不用在每个<li>节点上定义监听函数。而且以后再添加子节点,监听函数依然有效。

另外,我们可以使用stopPorpagation方法来使事件传播到某个节点就停下来,不再传播

// stopPropagation不会停止在同一个element上的其他事件的执行
p.addEventListener('click', function (event) {
  event.stopPropagation();
  console.log(1);
});

p.addEventListener('click', function(event) {
  // 会触发
  console.log(2);
});
  • 如果我们想不触发同一个element上的其他监听函数,可以使用stopImmediatePropogation()方法

1.3 事件对象

事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有事件都是这个对象的实例,即继承了Event.prototype

  • Event构造函数: event = new Event(type, option);
    • type 一个字符串,表示事件的名称
    • options 一个对象,表示事件对象的配置
      • bubbles boolean
        • default to false
        • 表示对象是否冒泡
      • cancelable boolean
        • default to false
        • 表示事情能否被取消,即能否用event.preventDefault()取消这个时间

1.3.1 实例属性

  • Event.bubbles
    • boolean
    • 表示当前事件是否会冒泡
    • 只读属性,用于了解Event实例是否可以冒泡
  • Event.eventPhase
    • 返回当前事件所处的阶段,该属性只读
      • 0 还没有发生
      • 1 捕获阶段 处于从祖先节点向目标节点的传播过程当中
      • 2 事件到达目标节点
      • 3 事件处于冒泡阶段
  • Event.currentTarget
    • 正在通过的节点
  • Event.target
    • 事件的原始触发节点
  • Event.timeStamp
  • Event.isTrusted
    • 表示该事件是否由一个真实的用户行为产生
  • Event.detail
    • 只有浏览器的UI事件才具有
    • 返回一个数值表示事件的某种信息
    • 具体含义与事件类型相关
      • 点击 次数
      • 鼠标滚轮 距离

1.3.2 实例方法

  • event.preventDefault()
    • 取消浏览器对当前事件的默认行为
    • 生效的前提是事件对象的cancelable属性为true
// HTML 代码为
// <input type="text" id="my-input" />
// 实现只接受小写的功能
var input = document.getElementById('my-input');
input.addEventListener('keypress', checkName, false);

function checkName(e) {
  if (e.charCode < 97 || e.charCode > 122) {
    e.preventDefault();
  }
}
  • event.stopPropagation()
    • 阻止事件在DOM中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数
  • event.stopImmediatePropogation()
    • 阻止同一个事件的其他监听函数被调用
    • 更彻底的阻止事件的传播
  • event.composedPath()
    • 返回一个数组
    • 成员是事件的最底层节点和依次冒泡经过的所有上层节点
// HTML 代码如下
// <div>
//   <p>Hello</p>
// </div>
var div = document.querySelector('div');
var p = document.querySelector('p');

div.addEventListener('click', function (e) {
  console.log(e.composedPath());
}, false);
// [p, div, body, html, document, Window]

1.4 各类事件的描述

1.4.1 鼠标事件

  • 继承MouseEvent接口
    • click
      • mouseDown + mouseUp
    • dblclick 在用一个元素上双击鼠标时触发
      • mouseDown + mouseUp + click
    • mousedown 按下鼠标键时触发
    • mouseup 释放按下的鼠标键的时候触发
    • mousemove
      • 当鼠标在一个结点内部移动的时候触发
      • 当鼠标持续移动时,就会持续触发
      • 应当对该事件的监听函数做一些限定,比如一定时间内只能运行一次
    • mouseenter
      • 进入一个节点时触发
    • mouseover
      • 鼠标进入一个节点时触发,进入子节点会再一次触发这个事件
    • mouseout
      • 鼠标离开一个节点的时候触发,离开父节点也会触发
    • mouseleave
      • 鼠标离开一个节点时触发,离开父节点不会触发这个事件
    • contextmenu
      • 按下鼠标右键时触发的
    • wheel
      • 滚动鼠标的滚轮时触发的,该事件继承的是WheelEvent接口
  • mouseEvent
    • 浏览器提供一个MouseEvent构造函数,用于新建一个MouseEvent实例
    • var event = new MouseEvent(type, options);
    • 第一个参数为字符串,表示事件名称
    • 第二个参数是一个事件配置对象,可以配一些不同的属性
      • screenX
      • screenY
      • clientX
        • 相对于程序窗口的水平位置
      • clientY
        • 相对于程序窗口的垂直位置
      • ctrlKey
      • shiftKey
      • altKey
      • metaKey
      • button
        • 0 按下主键
        • 1 按下辅助键
        • 2 按下次要键
      • buttons

1.4.2 键盘事件

  • 键盘事件的种类

    • keydown

      • 按下键盘的时候触发
    • keypress

      • 按下有值的键再触发,即按下Ctrl, Alt, Shift, Meta这样的无值的键不会触发
      • 对于有值的键,还是会先触发keydown事件,再触发这个事件
    • keyup

      • 松开键盘的时候触发该事件
      • 如果一直不松开按键,那么就会连续触发键盘事件
        • 触发顺序:
          • keydown
          • keypress
          • keydown
          • keypress
          • ….
          • 放开 -> keyup
  • KeyboardEvent 接口概述

    • 描述用户与键盘的互动
    • 继承了Event接口,并且定义了自己的实例属性和实例方法
    • 浏览器原生提供KeyboardEvent构造函数,用来新建键盘事件的实例
    • new KeyboardEvent(type, options)
    • 第一个参数为字符串,表示事件类型
    • 第二个参数为一个事件配置对象,参数可选
      • key
      • code
        • 0-9 digital0-digital9
        • A-Z KeyA - KeyZ
        • F1 - F12
        • 方向键
          • ArrowDown
          • ArrowUp
          • ArrowLeft
          • ArrowRight
        • Alt
          • AltLeft/ AltRight
          • similar to shift, ctrl
      • location
        • 返回键盘的区域
      • ctrlKey
      • shiftKey
      • altKey
      • metaKey
      • repeat
        • 看该案件是否被按着不放,以便判断是否重复这个键
  • KeyboardEvent实例方法

    • getModifierState()
      • 返回一个布尔值,表示是否按下或激活指定的功能键
        • alt
        • capslock
        • control
        • meta
        • numlock
        • shift

1.4.3 进度事件

用来描述资源加载的进度,主要由:

  • AJAX请求
  • <img>
  • <audio>
  • <video>
  • <style>
  • <link>

该类外部资源的加载触发,继承了ProgressEvent接口。主要包含以下几种事件:

  • abort 外部资源中止加载时被触发
  • error 由于错误导致外部资源无法加载时触发
  • load 外部资源加载成功时触发
  • loadstart 外部资源开始加载时触发
  • loadend 外部资源停止加载时触发
  • progress 外部资源加载过程中不断触发
  • timeout 加载超时时触发
  • ProgressEvent接口

    • 用来描述外部资源加载的进度
    • new ProgressEvent(type, options)
      • types 事件类型
      • options - 配置对象
        • lengthComputable 布尔值,表示加载的总量是否可以计算,默认为false
        • loaded 表示已经加载的量
        • total 表示需要加载的量

          1.4.4 表单事件

  • 表单事件的种类

    • input
      • <input>, <select>, <textarea>的值发生变化时触发
      • input事件会连续触发,每按下一个键,都会触发一次input事件的
    • select
      • 是在<input> <select> <textarea>里面的值发生变化的时候触发
    • change
      • 在元素失去焦点时发生
      • 即当有连续变化的时候,input事件会被触发很多次,而change事件只在失去焦点的时候被触发一次。
      • 换个角度看,input事件是一定伴随着change事件的,具体分为以下几种情况
        • 激活单选框或复选框时触发
        • 用户提交时触发
        • 当文本框或textarea元素的值发生改变,并且失去焦点的时候触发
    • invalid
      • 用户提交表单,当表单元素的值不满足校验条件,就会触发invalid事件
    • reset
      • 发生在表单对象上
      • 表示表单重置时锁触发的事件
    • submit
      • 当表单数据向服务器提交时触发
  • inputEvent接口

    • new InputEvent(type, options)
    • type 字符串,表示事件名称
    • options 配置对象
      • inputType
      • data 表示插入的字符串
      • dataTransfer

1.4.5 触摸事件

  • 触摸操作

    • touch 一个触摸点
      • 位置
      • 大小
      • 形状
      • 压力
      • 目标元素
    • touchList 多个触摸点的集合
      • 成员为Touch的实例对象
      • 属性
        • length 表示触摸点的数量
        • item() 返回指定的成员
    • touchEvent 触摸引发的事件实例
  • Touch 接口概述

    • var touch = new Touch(touchOptions)
    • touchOptions
      • identifier
        • 触摸点的唯一ID
      • target
      • clientX
      • clientY
      • screenX
      • screenY
      • pageX
      • pageY
      • radiusX
      • radiusY
      • rotationAngle
      • force
        • 0 -1 范围
        • 表示触摸压力
  • 触摸事件的种类

    • touchstart
    • touchend
    • touchmove
    • touchcancel

      1.4.6 拖拉事件

  • 拖拉定义

    • 用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里
  • 拖拉的对象

    • 元素节点
    • 图片
    • 链接
    • 选中的文字

1.4.7 其他常见事件

  • 资源事件
    • beforeunload
      • 在窗口,文档,各种资源将要卸载前触发
      • 用于防止用户不小心卸载资源
    • unload
      • 在窗口关闭或者document对象将要卸载时触发
      • 触发顺序排在beforeunload, pagehide事件后面
    • load
      • 在页面或者某个资源加载成功时触发
      • 页面或者资源从浏览器缓存加载,并不会触发load事件
  • session历史事件
    • pageshow
      • 页面加载时触发,如果要指定页面每次加载时都运行的打字吗,可以放在这个事件的监听函数当中
    • pagehide
    • popstate
      • 在浏览器的history对象的当前记录发生显式切换时触发
    • hashchange
      • URL的hash部分发生变化的时候触发
  • 网页状态事件
    • DOMContentLoaded 事件
      • 网页下载并解析完成以后在document对象上触发该事件
  • 窗口事件
    • scroll
      • 用户拖动滚动条
    • resize
    • fullscreenchange
    • fullscreenerror
  • 焦点事件
    • focus 获得焦点以后触发
    • blur 失去焦点以后触发
    • focusin 将要获得焦点时触发
    • focusout 将要失去焦点时触发

2. 浏览器模型

主要来介绍浏览器提供的各种JS接口

2.1 浏览器环境概述

  • 代码嵌入网页方法
目录
×

喜欢就点赞,疼爱就打赏