JavaScript红皮书学习(13)--事件

Posted by liveipool on January 13, 2017

事件

13.0.png

13.1 事件流

13.11.png

也就是说,事件流描述的是从页面中接收事件的顺序.

13.1.1 事件冒泡

13.1.1.png

13.1.2 事件捕获

13.1.21.png
13.1.22.png

13.1.3 DOM事件流

13.1.31.png
13.1.32.png

一般来说,尽量在冒泡阶段处理事件!

13.2 事件处理程序

  • 事件就是用户或浏览器自身执行的某种动作,如click等.
  • 响应某个事件的函数就叫做事件处理程序(或事件侦听器).
  • 事件处理程序的名字以”on”开头,因此click事件的事件处理程序就是onclick.

13.2.1 HTML事件处理程序

某个元素支持的每种事件,都可以有一个与相应事件处理程序同名的HTML特性来指定.

<input type="button" value="click me" onclick="alert('Clicked')" />
<input type="button" value="click me" onclick="showMessage()" />

这样指定事件处理程序具有一些独到之处.首先,这样会创建一个封装着元素属性值的函数.这个函数中有一个局部变量event,也就是事件对象.
13.2.1.png

但是,这样指定事件处理程序有几个缺点:

  1. 存在一个时差问题,用户可能在HTML元素一出现在页面上就触发相应的事件,但当时的事件处理程序可能还未具备执行条件.
  2. 不符合SOC的原则,HTML和JavaScript的耦合太紧.

13.2.2 DOM 0级事件处理程序

通过JavaSctript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性.如:

var btn = document.getElementById("myBtn");
btn.onclick = function() {
	alert("click");
}

13.2.21.png

以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理.

13.2.22.png

13.2.3 DOM 2级事件处理程序

13.2.31.png

	var btn = document.getElementById("myBtn");
	btn.addEventListener("click", function() {
		console.log(this.id);
	}, false);  //myBtn

13.2.32.png

	var btn = document.getElementById("myBtn");
	btn.addEventListener("click", function() {
		console.log(this.id);
	}, false);  //myBtn
		btn.addEventListener("click", function() {
		console.log("hello world");
	}, true);   //hello world

注意,上面这段代码会按照顺序输出两排,第一排是myBtn,第二排是hello world.

13.2.33.png

	var btn = document.getElementById("myBtn");
	btn.addEventListener("click", function() {
		console.log("hello world");
	}, false);   //hello world
	btn.removeEventListener("click", function() {
		console.log("hello world");
	}, false);   //没有用,还是能够输出hello world

13.2.34.png

13.2.4 IE事件处理程序

13.2.4.png

但是,由于只有IE支持这种方法,并且它和DOM方法在一些地方有所不同,所以看一下就好了,别用.

13.2.5 跨浏览器的事件处理程序

13.2.51.png
13.2.52.png
13.2.53.png

然而,现代浏览器(IE9, firefox, chrome, opera, safari, edge)都已经支持DOM2事件了,所以这种需要进行能力检测的时候也不是太多,了解一下上面这一段就行了,以后实在需要考虑旧版本浏览器的时候再用.

13.3 事件对象

13.3.png
如下面的代码在chrome, opera中都可以,但在firefox下会报错:

	btn.addEventListener("click", function() {
		console.log(event.eventPhase);
	}, false);   //2

这是因为firefox中的event只能在事件发生的现场使用,需要在调用函数时传入event对象:

	btn.addEventListener("click", function(event) {
		console.log(event.eventPhase);
	}, false);   //2

以后要使用event时尽量都将event写进函数参数中.IE中的event使用有所不同,后面会说到.

13.3.1 DOM中的事件对象

13.3.11.png
13.3.12.png
13.3.13.png
13.3.14.png
13.3.15.png
13.3.16.png
13.3.17.png
13.3.18.png

注意,只有在事件处理程序执行期间,event对象才会存在,一旦事件处理程序执行完成,event对象就会被销毁.

13.3.2 IE中的事件对象

13.3.21.png
13.3.22.png

13.3.3 跨浏览器的事件对象

13.3.31.png
13.3.32.png

然而,以上代码也只是红皮书上的一个示例,由于写书至今已经发生了很多变化,所以这段代码也不一定还合适,但最重要的还是要学习这种思想和方法,在要实现一些跨浏览器的功能时,可采用这种模式,并且是重要记住,是进行能力检测,而不是浏览器检测.

13.4 事件类型

13.4.png

这一节的内容有需要使用时就参考官方文档: https://www.w3.org/TR/uievents/

13.4.1 UI事件

UI事件指的是那些不一定与用户操作有关的事件,现有的UI事件如下:
13.4.1.png
最常用的就是load事件,其他的用得不多.

13.4.2 焦点事件

焦点事件会在页面元素获得或时区焦点时触发.利用这些事件与document,.hasFocus()方法以及document.activeElement属性配合,可以知晓用户在页面上的行踪.
这一类事件中最主要的两个是focus和blur,它们都是JavScript早期就得到所有浏览器支持的事件,但它们两个事件最大的问题是它们不冒泡.因此,DOM3级事件引入了两个新的事件,它们支持冒泡: focusin和focusout.

13.4.3 鼠标与滚轮事件

13.4.31.png
13.4.32.png

鼠标事件中还有一类滚轮事件,其中也只有一个mousewheel事件,这个事件跟踪鼠标滚轮,类似于Mac的触控版.(具体使用去mdn查)
和鼠标事件相关的一些需要了解的内容:
1. 客户区坐标位置:
鼠标时间都是在浏览器视口中的特定位置上发生的,这个位置信息保存在事件对象的clientX和clientY中.(是相对客户区的坐标,比如上面不会包括那些选项栏的高度)

2. 屏幕坐标位置:
鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置: screenX和screenY属性.

3. 修改键:
13.4.33.png

4. 鼠标按钮:
13.4.34.png

5. detail属性:
“DOM2级事件”规范在event对象中还提供了detail属性,用于给出有关事件的更多信息,对于鼠标事件来说,detail中包含了一个数值,表示在给定位置上发生了多少次单击.

13.4.4 键盘与文本事件

13.4.41.png
KeyboardEvent.key属性可以得到按下的键的值.

13.4.5 复合事件

复合事件(composition event)是DOM3级事件中新添加的一类事件,用于处理IME的输入序列.IME(Input Method Editor, 输入法编辑器)可以让用户输入在物理键盘上找不到的字符.
暂时不用深究,知道有个这个东西就好.

13.4.6 变动事件

DOM2级的变动(mutation)事件能在DOM中的某一部分发生变化时给出提示,有如下事件:
13.4.6.png

13.4.7 HTML5事件

DOM规范没有涵盖所有浏览器支持的所有时间,很多浏览器出于不同的目的–满足用户需求或解决特殊问题,还实现了一些自定义的事件.(下文只说一个现代浏览器都支持的事件:)
hashchange 事件:
13.4.7.png

13.4.8 设备事件

13.4.8.png

暂时还没有这方面的开发经历,以后可以在具体项目中试一下.

13.4.9 触摸与手势事件

也需要在以后的项目中进行实践.

13.5 内存和性能

13.5.png

13.5.1 事件委托

13.5.12.png
13.5.13.png
13.5.14.png
13.5.15.png

我在studying-fram里面试着写了一下,为每个li分别添加事件的写法时的处理时间:
13.5.11.png

改为事件委托写法之后,整个时间大概少了30ms,由于现在的例子中操作的DOM的数量不多,所以区别不大,但还是能看出有一些区别的,当项目大了之后这个的影响就会很大,因此要学会事件委托这种写法.

13.5.2 移除事件处理程序

13.5.21.png
13.5.22.png

13.6 模拟事件

13.6.png

看了之后感觉并不是太好用,也不知道在哪些情况下比较适用,感觉上是在开发时可以用来调试,但有点麻烦不如自己进行事件,了解一下就好.

13.7 小结

13.7.png

相关文章链接