JS事件原理是怎样的?

简介: 笔记

2、MouseEvent 接口概述

MouseEvent接口代表所有鼠标事件所产生的对象都是MouseEvent实例。此外,滚轮事件和拖拉事件也是MouseEvent实例。

MouseEvent接口继承了Event接口,所以拥有Event的所有属性和方法。它还有自己的属性和方法。

浏览器原生提供一个MouseEvent构造函数,用于新建一个MouseEvent实例。

var event = new MouseEvent(type, options);// 参数一,事件名称字符串;参数二,事件配置对象

MouseEvent构造函数接受两个参数。第一个参数是字符串,表示事件名称;第二个参数是一个事件配置对象,该参数可选。除了Event接口的实例配置属性,该对象可以配置以下属性,所有属性都是可选的。

  • screenX:数值,鼠标相对于屏幕的水平位置(单位像素),默认值为0,设置该属性不会移动鼠标。
  • screenY:数值,鼠标相对于屏幕的垂直位置(单位像素),其他与screenX相同。
  • clientX:数值,鼠标相对于程序窗口的水平位置(单位像素),默认值为0,设置该属性不会移动鼠标。
  • clientY:数值,鼠标相对于程序窗口的垂直位置(单位像素),其他与clientX相同。
  • ctrlKey:布尔值,是否同时按下了 Ctrl 键,默认值为false
  • shiftKey:布尔值,是否同时按下了 Shift 键,默认值为false
  • altKey:布尔值,是否同时按下 Alt 键,默认值为false
  • metaKey:布尔值,是否同时按下 Meta 键(win键),默认值为false
  • button:数值,表示按下了哪一个鼠标按键,默认值为0,表示按下主键(通常是鼠标的左键)或者当前事件没有定义这个属性;1表示按下辅助键(通常是鼠标的中间键),2表示按下次要键(通常是鼠标的右键)。
  • buttons:数值,表示按下了鼠标的哪些键,是一个三个比特位的二进制值,默认为0(没有按下任何键)。1(二进制001)表示按下主键(通常是左键),2(二进制010)表示按下次要键(通常是右键),4(二进制100)表示按下辅助键(通常是中间键)。因此,如果返回3(二进制011)就表示同时按下了左键和右键。
  • relatedTarget:节点对象,表示事件的相关节点,默认为nullmouseentermouseover事件时,表示鼠标刚刚离开的那个元素节点;mouseoutmouseleave事件时,表示鼠标正在进入的那个元素节点。

下面是一个例子。

var event = new MouseEvent('click2', {
    'bubbles': true,
    'cancelable': true
});
var cb = document.getElementById('checkbox');
cb.addEventListener('click2',function(){ // 绑定事件监听函数
    console.log(22) // 被执行
})
cb.dispatchEvent(event);// 触发事件

上面代码生成一个鼠标点击事件,并触发该事件。

3、MouseEvent 接口的实例属性

3.1 MouseEvent.altKey,MouseEvent.ctrlKey,MouseEvent.metaKey,MouseEvent.shiftKey

MouseEvent.altKeyMouseEvent.ctrlKeyMouseEvent.metaKeyMouseEvent.shiftKey这四个属性都返回一个布尔值,表示事件发生时,是否按下对应的键。它们都是只读属性。

  • altKey属性:Alt 键
  • ctrlKey属性:Ctrl 键
  • metaKey属性:Meta 键(Mac 键盘是一个四瓣的小花,Windows 键盘是 Windows 键)
  • shiftKey属性:Shift 键
// HTML 代码如下
// <body onclick="showKey(event)">
function showKey(e) {
  console.log('ALT key pressed: ' + e.altKey);
  console.log('CTRL key pressed: ' + e.ctrlKey);
  console.log('META key pressed: ' + e.metaKey);
  console.log('SHIFT key pressed: ' + e.shiftKey);
}

上面代码中,点击网页会输出是否同时按下对应的键。

3.2 MouseEvent.button 鼠标的哪个键,MouseEvent.buttons同时按哪些键

MouseEvent.button属性返回一个数值,表示事件发生时按下了鼠标的哪个键。该属性只读

  • 0:按下主键(通常是左键),或者该事件没有初始化这个属性(比如mousemove事件)。
  • 1:按下辅助键(通常是中键或者滚轮键)。
  • 2:按下次键(通常是右键)。
// HTML 代码为
// <button onmouseup="whichButton(event)">点击</button>
var whichButton = function (e) {
  switch (e.button) {
    case 0:
      console.log('Left button clicked.');
      break;
    case 1:
      console.log('Middle button clicked.');
      break;
    case 2:
      console.log('Right button clicked.');
      break;
    default:
      console.log('Unexpected code: ' + e.button);
  }
}

MouseEvent.buttons属性返回一个三个比特位的值,表示同时按下了哪些键。它用来处理同时按下多个鼠标键的情况。该属性只读

  • 1:二进制为001(十进制的1),表示按下左键。
  • 2:二进制为010(十进制的2),表示按下右键。
  • 4:二进制为100(十进制的4),表示按下中键或滚轮键。

同时按下多个键的时候,每个按下的键对应的比特位都会有值。比如,同时按下左键和右键,会返回3(二进制为011)。

document.body.addEventListener('mousemove',function(e){ // 注意,用click时一直都是0
    console.log(e.buttons)
})
// 未按下任何键时是 0
// 按下左键 1  (001)
// 按下右键 2  (010)
// 按下中键 4  (100)
// 按下左键和右键 3  (011)
// 按下左键和中键 5  (101)
// 按下右键和中键 6  (110)
// 按下左、中、右键 7  (111)

3.3 MouseEvent.clientX 相对浏览器X坐标,MouseEvent.clientY 相对浏览器Y坐标

MouseEvent.clientX属性返回鼠标位置相对于浏览器窗口左上角的水平坐标(单位像素),MouseEvent.clientY属性返回垂直坐标。这两个属性都是只读属性。

// HTML 代码为
// <body onmousedown="showCoords(event)">
function showCoords(evt){
  console.log(
    'clientX value: ' + evt.clientX + '\n' +
    'clientY value: ' + evt.clientY + '\n'
  );
}

这两个属性还分别有一个别名MouseEvent.xMouseEvent.y

3.4 MouseEvent.movementX 上一个鼠标经过事件的X距离,MouseEvent.movementY 上一个鼠标经过事件的Y距离

MouseEvent.movementX属性返回当前位置与上一个mousemove事件之间的水平距离(单位像素)。数值上,它等于下面的计算公式。

currentEvent.movementX = currentEvent.screenX - previousEvent.screenX

MouseEvent.movementY属性返回当前位置与上一个mousemove事件之间的垂直距离(单位像素)。数值上,它等于下面的计算公式。

currentEvent.movementY = currentEvent.screenY - previousEvent.screenY。

这两个属性都是只读属性。

3.5 MouseEvent.screenX 相对屏幕X坐标,MouseEvent.screenY 相对屏幕Y坐标

MouseEvent.screenX属性返回鼠标位置相对于屏幕左上角的水平坐标(单位像素),MouseEvent.screenY属性返回垂直坐标。这两个属性都是只读属性。

// HTML 代码如下
// <body onmousedown="showCoords(event)">
function showCoords(evt) {
  console.log(
    'screenX value: ' + evt.screenX + '\n',
    'screenY value: ' + evt.screenY + '\n'
  );
}

3.6 MouseEvent.offsetX 偏移量X,MouseEvent.offsetY 偏移量Y

MouseEvent.offsetX属性返回鼠标位置与目标节点左侧的padding边缘的水平距离(单位像素),MouseEvent.offsetY属性返回与目标节点上方的padding边缘的垂直距离。这两个属性都是只读属性。

/* HTML 代码如下
  <style>
    p {
      width: 100px;
      height: 100px;
      padding: 100px;
    }
  </style>
  <p>Hello</p>
*/
var p = document.querySelector('p');
p.addEventListener(
  'click',
  function (e) {
    console.log(e.offsetX); // 包含padding
    console.log(e.offsetY);
  },
  false
);

上面代码中,鼠标如果在p元素的中心位置点击,会返回150 150。因此中心位置距离左侧和上方的padding边缘,等于padding的宽度(100像素)加上元素内容区域一半的宽度(50像素)。

3.7 MouseEvent.pageX 文档X坐标,MouseEvent.pageY 文档Y坐标

MouseEvent.pageX属性返回鼠标位置与文档左侧边缘的距离(单位像素),MouseEvent.pageY属性返回与文档上侧边缘的距离(单位像素)。它们的返回值都包括文档不可见的部分。这两个属性都是只读

/* HTML 代码如下
  <style>
    body {
      height: 2000px;
    }
  </style>
*/
document.body.addEventListener(
  'click',
  function (e) {
    console.log(e.pageX);
    console.log(e.pageY);
  },
  false
);

上面代码中,页面高度为2000像素,会产生垂直滚动条。滚动到页面底部,点击鼠标输出的pageY值会接近2000。

3.8 MouseEvent.relatedTarget 事件的相关节点

MouseEvent.relatedTarget属性返回事件的相关节点。对于那些没有相关节点的事件,该属性返回null。该属性只读

下表列出不同事件的target属性值和relatedTarget属性值义。

事件名称 target 属性 relatedTarget 属性
focusin 接受焦点的节点 丧失焦点的节点
focusout 丧失焦点的节点 接受焦点的节点
mouseenter 将要进入的节点 将要离开的节点
mouseleave 将要离开的节点 将要进入的节点
mouseout 将要离开的节点 将要进入的节点
mouseover 将要进入的节点 将要离开的节点
dragenter 将要进入的节点 将要离开的节点
dragexit 将要离开的节点 将要进入的节点

下面是一个例子。

/*
  HTML 代码如下
  <div id="outer" style="height:50px;width:50px;border-width:1px solid black;">
    <div id="inner" style="height:25px;width:25px;border:1px solid black;"></div>
  </div>
*/
var inner = document.getElementById('inner');
inner.addEventListener('mouseover', function (event) {
  console.log('进入' + event.target.id + ' 离开' + event.relatedTarget.id);
}, false);
inner.addEventListener('mouseenter', function (event) {
  console.log('进入' + event.target.id + ' 离开' + event.relatedTarget.id);
});
inner.addEventListener('mouseout', function () {
  console.log('离开' + event.target.id + ' 进入' + event.relatedTarget.id);
});
inner.addEventListener("mouseleave", function (){
  console.log('离开' + event.target.id + ' 进入' + event.relatedTarget.id);
});
// 鼠标从 outer 进入inner,输出
// 进入inner 离开outer
// 进入inner 离开outer
// 鼠标从 inner进入 outer,输出
// 离开inner 进入outer
// 离开inner 进入outer

4、MouseEvent 接口的实例方法

4.1 MouseEvent.getModifierState() 是否按下指定功能键

MouseEvent.getModifierState方法返回一个布尔值,表示有没有按下特定的功能键。它的参数是一个表示功能键的字符串。

document.addEventListener('click', function (e) {
  console.log(e.getModifierState('CapsLock'));
}, false);

上面的代码可以了解用户是否按下了大写键。

5、WheelEvent 接口 (滚轮)

5.1 概述

WheelEvent 接口继承了 MouseEvent 实例,代表鼠标滚轮事件的实例对象。目前,鼠标滚轮相关的事件只有一个wheel事件,用户滚动鼠标的滚轮,就生成这个事件的实例。

浏览器原生提供WheelEvent()构造函数,用来生成WheelEvent实例。

var wheelEvent = new WheelEvent(type, options);

WheelEvent()构造函数可以接受两个参数,第一个是字符串,表示事件类型,对于滚轮事件来说,这个值目前只能是wheel。第二个参数是事件的配置对象。该对象的属性除了EventUIEvent的配置属性以外,还可以接受以下几个属性,所有属性都是可选的。

  • deltaX:数值,表示滚轮的水平滚动量,默认值是 0.0。
  • deltaY:数值,表示滚轮的垂直滚动量,默认值是 0.0。
  • deltaZ:数值,表示滚轮的 Z 轴滚动量,默认值是 0.0。
  • deltaMode:数值,表示相关的滚动事件的单位,适用于上面三个属性。0表示滚动单位为像素,1表示单位为行,2表示单位为页,默认为0

5.2 实例属性

WheelEvent事件实例除了具有EventMouseEvent的实例属性和实例方法,还有一些自己的实例属性,但是没有自己的实例方法。

下面的属性都是只读属性。

  • WheelEvent.deltaX:数值,表示滚轮的水平滚动量。
  • WheelEvent.deltaY:数值,表示滚轮的垂直滚动量。
  • WheelEvent.deltaZ:数值,表示滚轮的 Z 轴滚动量。
  • WheelEvent.deltaMode:数值,表示上面三个属性的单位,0是像素,1是行,2是页。

五、键盘事件

1、键盘事件的种类

键盘事件由用户击打键盘触发,主要有keydownkeypresskeyup三个事件,它们都继承了KeyboardEvent接口。

  • keydown:按下键盘时触发。【按下】
  • keypress:按下有值的键时触发,即按下 Ctrl、Alt、Shift、Meta 这样无值的键,这个事件不会触发。对于有值的键,按下时先触发keydown事件,再触发这个事件。【按下有值的键】
  • keyup:松开键盘时触发该事件。【松开】

如果用户一直按键不松开,就会连续触发键盘事件,触发的顺序如下。

  1. keydown
  2. keypress
  3. keydown
  4. keypress
  5. ...(重复以上过程)
  6. keyup

2、KeyboardEvent 接口概述

KeyboardEvent接口用来描述用户与键盘的互动。这个接口继承了Event接口,并且定义了自己的实例属性和实例方法。

浏览器原生提供KeyboardEvent构造函数,用来新建键盘事件的实例。

new KeyboardEvent(type, options) // 参数一,事件类型;参数二,事件配置对象

KeyboardEvent构造函数接受两个参数。第一个参数是字符串,表示事件类型;第二个参数是一个事件配置对象,该参数可选。除了Event接口提供的属性,还可以配置以下字段,它们都是可选。

  • key:字符串,当前按下的键,默认为空字符串。【键名】
  • code:字符串,表示当前按下的键的字符串形式,默认为空字符串。【键码】
  • location:整数,当前按下的键的位置,默认为0
  • ctrlKey:布尔值,是否按下 Ctrl 键,默认为false
  • shiftKey:布尔值,是否按下 Shift 键,默认为false
  • altKey:布尔值,是否按下 Alt 键,默认为false
  • metaKey:布尔值,是否按下 Meta 键,默认为false
  • repeat:布尔值,是否重复按键,默认为false

3、KeyboardEvent 的实例属性

3.1 KeyboardEvent.altKey,KeyboardEvent.ctrlKey,KeyboardEvent.metaKey,KeyboardEvent.shiftKey 【是否按下对应键,布尔值】

以下属性都是只读属性,返回一个布尔值,表示是否按下对应的键。

  • KeyboardEvent.altKey:是否按下 Alt 键
  • KeyboardEvent.ctrlKey:是否按下 Ctrl 键
  • KeyboardEvent.metaKey:是否按下 meta 键(Mac 系统是一个四瓣的小花,Windows 系统是 windows 键)
  • KeyboardEvent.shiftKey:是否按下 Shift 键

下面是一个示例。

function showChar(e) {
  console.log('ALT: ' + e.altKey);
  console.log('CTRL: ' + e.ctrlKey);
  console.log('Meta: ' + e.metaKey);
  console.log('Shift: ' + e.shiftKey);
}
document.body.addEventListener('keydown', showChar, false);

3.2 KeyboardEvent.code 键码

KeyboardEvent.code属性返回一个字符串,表示当前按下的键的字符串形式。该属性只读

下面是一些常用键的字符串形式,其他键请查文档

  • 数字键0 - 9:返回digital0 - digital9
  • 字母键A - z:返回KeyA - KeyZ
  • 功能键F1 - F12:返回 F1 - F12
  • 方向键:返回ArrowDownArrowUpArrowLeftArrowRight
  • Alt 键:返回AltLeftAltRight
  • Shift 键:返回ShiftLeftShiftRight
  • Ctrl 键:返回ControlLeftControlRight

3.3 KeyboardEvent.key 键名

KeyboardEvent.key属性返回一个字符串,表示按下的键名。该属性只读

如果按下的键代表可打印字符,则返回这个字符,比如数字、字母。

如果按下的键代表不可打印的特殊字符,则返回预定义的键值,比如 Backspace,Tab,Enter,Shift,Control,Alt,CapsLock,Esc,Spacebar,PageUp,PageDown,End,Home,Left,Right,Up,Down,PrintScreen,Insert,Del,Win,F1~F12,NumLock,Scroll 等。

如果同时按下一个控制键和一个符号键,则返回符号键的键名。比如,按下 Ctrl + a,则返回a;按下 Shift + a,则返回大写的A

如果无法识别键名,返回字符串Unidentified

3.4 KeyboardEvent.location 键处于哪个位置,整数

KeyboardEvent.location属性返回一个整数,表示按下的键处在键盘的哪一个区域。它可能取以下值。

  • 0:处在键盘的主区域,或者无法判断处于哪一个区域。
  • 1:处在键盘的左侧,只适用那些有两个位置的键(比如 Ctrl 和 Shift 键)。
  • 2:处在键盘的右侧,只适用那些有两个位置的键(比如 Ctrl 和 Shift 键)。
  • 3:处在数字小键盘。

3.5 KeyboardEvent.repeat 是否长按

KeyboardEvent.repeat返回一个布尔值,代表该键是否被按着不放,以便判断是否重复这个键,即浏览器会持续触发keydownkeypress事件,直到用户松开手为止。

4、KeyboardEvent 的实例方法

4.1 KeyboardEvent.getModifierState() 是否按下指定功能键

KeyboardEvent.getModifierState()方法返回一个布尔值,表示是否按下或激活指定的功能键。它的常用参数如下。

  • Alt:Alt 键
  • CapsLock:大写锁定键
  • Control:Ctrl 键
  • Meta:Meta 键
  • NumLock:数字键盘开关键
  • Shift:Shift 键
if (
  event.getModifierState('Control') +
  event.getModifierState('Alt') +
  event.getModifierState('Meta') > 1
) {
  return;
}

上面代码表示,只要ControlAltMeta里面,同时按下任意两个或两个以上的键就返回。

六、进度事件

1、进度事件的种类

进度事件用来描述资源加载的进度,主要由 AJAX 请求、<img><audio><video><style><link>等外部资源的加载触发,继承了ProgressEvent接口。它主要包含以下几种事件

  • abort:外部资源中止加载时(比如用户取消)触发。如果发生错误导致中止,不会触发该事件。【中止加载】
  • error:由于错误导致外部资源无法加载时触发。【加载错误】
  • load:外部资源加载成功时触发。【加载成功】
  • loadstart:外部资源开始加载时触发。【开始加载】
  • loadend:外部资源停止加载时触发,发生顺序排在errorabortload等事件的后面。【停止加载】
  • progress:外部资源加载过程中不断触发。【加载中,不断触发】
  • timeout:加载超时时触发。【加载超时】

注意,除了资源下载,文件上传也存在这些事件

下面是一个例子。

image.addEventListener('load', function (event) { // 加载成功
  image.classList.add('finished');
});
image.addEventListener('error', function (event) { // 加载出错
  image.style.display = 'none';
});

上面代码在图片元素加载完成后,为图片元素添加一个finished的 Class。如果加载失败,就把图片元素的样式设置为不显示。

有时候,图片加载会在脚本运行之前就完成,尤其是当脚本放置在网页底部的时候,因此有可能loaderror事件的监听函数根本不会执行。所以,比较可靠的方式,是用complete属性先判断一下是否加载完成。

function loaded() {
  // ...
}
if (image.complete) { // 是否加载完成
  loaded();
} else {
  image.addEventListener('load', loaded); // 加载成功事件
}

由于 DOM 的元素节点没有提供是否加载错误的属性,所以error事件的监听函数最好放在<img>元素的 HTML 代码中,这样才能保证发生加载错误时百分之百会执行。

<img src="/wrong/url" onerror="this.style.display='none';" />

loadend事件的监听函数,可以用来取代abort事件、load事件、error事件的监听函数,因为它总是在这些事件之后发生。

req.addEventListener('loadend', loadEnd, false);
function loadEnd(e) {
  console.log('传输结束,成功失败未知');
}

loadend事件本身不提供关于进度结束的原因,但可以用它来做所有加载结束场景都需要做的一些操作。

另外,error事件有一个特殊的性质,就是不会冒泡。所以,子元素的error事件,不会触发父元素的error事件监听函数。

2、ProgressEvent 接口

2.1 概述

ProgressEvent接口主要用来描述外部资源加载的进度,比如 AJAX 加载、<img><video><style><link>等外部资源加载。进度相关的事件都继承了这个接口。这个接口继承了Event接口。

浏览器原生提供了ProgressEvent()构造函数,用来生成事件实例。

new ProgressEvent(type, options) // 参数一,事件类型;参数二,配置对象

ProgressEvent()构造函数接受两个参数。第一个参数是字符串,表示事件的类型,这个参数是必须的。第二个参数是一个配置对象,表示事件的属性,该参数可选。配置对象除了可以使用Event接口的配置属性,还可以使用下面的属性,所有这些属性都是可选的。

  • lengthComputable:布尔值,表示加载的总量是否可以计算,默认是false
  • loaded:整数,表示已经加载的量,默认是0
  • total:整数,表示需要加载的总量,默认是0

2.2 ProgressEvent的实例属性。

  • ProgressEvent.lengthComputable总量是否可以计算
  • ProgressEvent.loaded已加载的量
  • ProgressEvent.total 需要加载的总量

如果ProgressEvent.lengthComputablefalseProgressEvent.total实际上是没有意义的。

下面是一个例子。

var p = new ProgressEvent('load', {
  lengthComputable: true,
  loaded: 30,
  total: 100,
});
document.body.addEventListener('load', function (e) {
  console.log('已经加载:' + (e.loaded / e.total) * 100 + '%');
});
document.body.dispatchEvent(p);
// 已经加载:30%

上面代码先构造一个load事件,抛出后被监听函数捕捉到。

下面是一个实际的例子。

var xhr = new XMLHttpRequest();
xhr.addEventListener('progress', updateProgress, false); // 加载中
xhr.addEventListener('load', transferComplete, false); // 加载成功
xhr.addEventListener('error', transferFailed, false); // 加载错误
xhr.addEventListener('abort', transferCanceled, false); // 中止加载
xhr.open();
function updateProgress(e) { // 加载中
  if (e.lengthComputable) { // 是否可以计算总量
    var percentComplete = e.loaded / e.total; // 加载进度计算
  } else {
    console.log('不能计算进度');
  }
}
function transferComplete(e) { // 加载成功
  console.log('传输结束');
}
function transferFailed(evt) { // 加载错误
  console.log('传输过程中发生错误');
}
function transferCanceled(evt) { // 中止加载
  console.log('用户取消了传输');
}

上面是下载过程的进度事件,还存在上传过程的进度事件。这时所有监听函数都要放在XMLHttpRequest.upload对象上面。

var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', updateProgress, false);
xhr.upload.addEventListener('load', transferComplete, false);
xhr.upload.addEventListener('error', transferFailed, false);
xhr.upload.addEventListener('abort', transferCanceled, false);
xhr.open();

七、表单事件

1、表单事件的种类

1.1 input 事件 (值发生变化触发,会连续)

input事件当<input><select><textarea>值发生变化时触发。对于复选框(<input type=checkbox>)或单选框(<input type=radio>),用户改变选项时,也会触发这个事件。另外,对于打开contenteditable属性的元素,只要值发生变化,也会触发input事件。

input事件的一个特点,就是会连续触发,比如用户每按下一次按键,就会触发一次input事件

input事件对象继承了InputEvent接口

该事件跟change事件很像,不同之处在于*input事件在元素的值发生变化后立即发生*change在元素失去焦点时发生,而内容此时可能已经变化多次。也就是说,如果有连续变化,input事件会触发多次,而change事件只在失去焦点时触发一次。

下面是<select>元素的例子。

/* HTML 代码如下
<select id="mySelect">
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
</select>
*/
function inputHandler(e) {
  console.log(e.target.value)
}
var mySelect = document.querySelector('#mySelect');
mySelect.addEventListener('input', inputHandler);

上面代码中,改变下拉框选项时,会触发input事件,从而执行回调函数inputHandler

1.2 select 事件 (选中文本时触发)

select事件当在<input><textarea>里面选中文本时触发

// HTML 代码如下
// <input id="test" type="text" value="Select me!" />
var elem = document.getElementById('test');
elem.addEventListener('select', function (e) {
  console.log(e.type); // "select" 事件类型
  var _target = e.target;
  console.log(_target.value); // 文本框的全部值
  console.log(_target.selectionDirection); // 选择的方向:'forward'正向、'backward'反向
  console.log(_target.selectionStart); // 开始选择的索引
  console.log(_target.selectionEnd); // 结束选择的索引
  // 注意:开始和结束索引是不分选择方向的,开始的索引一直是靠前的
  console.log(_target.value.slice(_target.selectionStart, _target.selectionEnd)) // 选中的那部分字符串
}, false);

选中的文本可以通过event.target元素的selectionDirectionselectionEndselectionStartvalue属性拿到。

1.3 change 事件 (值发生变化时触发,单次)

change事件当<input><select><textarea>值发生变化时触发。它与input事件的最大不同,就是不会连续触发,只有当全部修改完成时才会触发,另一方面input事件必然伴随change事件。具体来说,分成以下几种情况。

  • 激活单选框(radio)或复选框(checkbox)时触发。
  • 用户提交时触发。比如,从下列列表(select)完成选择,在日期或文件输入框完成选择。
  • 当文本框或<textarea>元素的值发生改变,并且丧失焦点时触发。

下面是一个例子。

// HTML 代码如下
// <select size="1" onchange="changeEventHandler(event);">
//   <option>chocolate</option>
//   <option>strawberry</option>
//   <option>vanilla</option>
// </select>
function changeEventHandler(event) {
  console.log(event.target.value);
}

如果比较一下上面input事件的例子,你会发现对于<select>元素来说,inputchange事件基本是等价的。

1.4 invalid 事件 (表单提交不满足条件触发)

用户提交表单时,如果表单元素的值不满足校验条件,就会触发invalid事件。

<form>
  <input type="text" required oninvalid="console.log('invalid input')" />
  <button type="submit">提交</button>
</form>

上面代码中,输入框是必填的。如果不填,用户点击按钮提交时,就会触发输入框的invalid事件,导致提交被取消。

1.5 reset 事件(重置),submit 事件(提交)

reset事件当表单重置(所有表单成员变回默认值)时触发。

submit事件当表单数据向服务器提交时触发

注意,这两个事件发生在表单对象<form>上,而不是发生在表单的成员上,因为提交的是表单,而不是表单成员。

<form onreset="console.log('触发了重置事件')" onsubmit="console.log('触发了提交事件')" name="input" action="html_form_action.php" method="get">
    <input type="text" name="lname" value="Duck">
    <button type="reset">重置</button>
    <button type="submit">提交</button>
</form>

2、InputEvent 接口(input事件的实例)

InputEvent接口主要用来描述input事件的实例。该接口继承了Event接口,还定义了一些自己的实例属性和实例方法。

浏览器原生提供InputEvent()构造函数,用来生成实例对象。

new InputEvent(type, options) // 参数一,事件名称;参数二,配置对象

InputEvent构造函数可以接受两个参数。第一个参数是字符串,表示事件名称,该参数是必需的。第二个参数是一个配置对象,用来设置事件实例的属性,该参数是可选的。配置对象的字段除了Event构造函数的配置属性,还可以设置下面的字段,这些字段都是可选的。

  • inputType:字符串,表示发生变更的类型(详见下文)。
  • data:字符串,表示插入的字符串。如果没有插入的字符串(比如删除操作),则返回null或空字符串。
  • dataTransfer:返回一个 DataTransfer 对象实例,该属性通常只在输入框接受富文本输入时有效

InputEvent的实例属性主要就是上面三个属性,这三个实例属性都是只读的

(1)InputEvent.data 变动的那部分内容

InputEvent.data属性返回一个字符串,表示变动的内容

// HTML 代码如下
// <input type="text" id="myInput">
var input = document.getElementById('myInput');
input.addEventListener('input', myFunction, false);
function myFunction(e) {
  console.log(e.data);
}

上面代码中,如果手动在输入框里面输入abc,控制台会先输出a,再在下一行输出b,再在下一行输出c。然后选中abc,一次性将它们删除,控制台会输出null或一个空字符串。

(2)InputEvent.inputType 变更类型

InputEvent.inputType属性返回一个字符串,表示字符串发生变更的类型

对于常见情况,Chrome 浏览器的返回值如下。完整列表可以参考文档

  • 手动插入文本:insertText
  • 粘贴插入文本:insertFromPaste
  • 向后删除:deleteContentBackward
  • 向前删除:deleteContentForward

(3)InputEvent.dataTransfer

InputEvent.dataTransfer属性返回一个 DataTransfer 实例。该属性只在文本框接受粘贴内容(insertFromPaste)或拖拽内容(insertFromDrop)时才有效

相关文章
|
30天前
|
JavaScript 前端开发
js事件队列
js事件队列
|
19天前
|
JavaScript 前端开发
JavaScript 事件
JavaScript 事件
27 2
|
1天前
|
JavaScript 前端开发
JavaScript HTML DOM 事件
JavaScript HTML DOM 事件
12 5
|
2天前
|
监控 JavaScript 前端开发
|
5天前
|
前端开发 JavaScript Java
JavaScript的运行原理
JavaScript 的运行原理包括代码输入、解析、编译、执行、内存管理和与浏览器交互几个步骤。当打开网页时,浏览器加载 HTML、CSS 和 JavaScript 文件,并通过 JavaScript 引擎将其解析为抽象语法树(AST)。接着,引擎将 AST 编译成字节码或机器码,并在执行阶段利用事件循环机制处理异步操作,确保单线程的 JavaScript 能够高效运行。同时,JavaScript 引擎还负责内存管理和垃圾回收,以减少内存泄漏。通过与 DOM 的交互,JavaScript 实现了动态网页效果,提供了灵活且高效的开发体验。
|
10天前
|
存储 JavaScript 前端开发
[JS] ES Modules的运作原理
【9月更文挑战第16天】ES Modules(ECMAScript Modules)是 JavaScript 中的一种模块化开发规范,适用于浏览器和 Node.js 环境。它通过 `export` 和 `import` 关键字实现模块的导出与导入。模块定义清晰,便于维护和测试。JavaScript 引擎会在执行前进行静态分析,确保模块按需加载,并处理循环依赖。ES Modules 支持静态类型检查,现代浏览器已原生支持,还提供动态导入功能,增强了代码的灵活性和性能。这一规范显著提升了代码的组织和管理效率。
|
19天前
Nest.js 实战 (十二):优雅地使用事件发布/订阅模块 Event Emitter
这篇文章介绍了在Nest.js构建应用时,如何通过事件/发布-订阅模式使应用程序更健壮、灵活、易于扩展,并简化服务间通信。文章主要围绕@nestjs/event-emitter模块展开,这是一个基于eventemitter2库的社区模块,提供了事件发布/订阅功能,使得实现事件驱动架构变得简单。文章还介绍了如何使用该模块,包括安装依赖、初始化模块、注册EventEmitterModule、使用装饰器简化监听等。最后总结,集成@nestjs/event-emitter模块可以提升应用程序的事件驱动能力,构建出更为松耦合、易扩展且高度灵活的系统架构,是构建现代、响应迅速且具有高度解耦特性的Nest.
|
30天前
|
缓存 JavaScript 前端开发
[译] Vue.js 内部原理浅析
[译] Vue.js 内部原理浅析
|
1月前
|
JavaScript 前端开发 安全
JS 混淆解析:JS 压缩混淆原理、OB 混淆特性、OB 混淆JS、混淆突破实战
JS 混淆解析:JS 压缩混淆原理、OB 混淆特性、OB 混淆JS、混淆突破实战
42 2
|
1月前
|
编解码 JavaScript 前端开发
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
52 1