【笔记】JavaScript事件处理机制,元素大小判断与H5的媒体标签
前一阵舍友去面试,被问到JavaScript中的事件处理机制。暗自思忖,发现自己也没有深入的了解过。顺带连同常用的HTML元素大小和实际中用到的HTML5中的媒体元素简单整理在下面,方便之后回顾。
事件
JavaScript和HTML的交互是通过事件实现的。可以通过监听器订阅文档或窗口中的事件,在事件发生时执行特定的代码。这种属于设计模式中的观察者模式。
事件相关的API最早出现在IE4和NetScape Nivagator4(后面简称为网景)中。两种浏览器提供了相似却不同的API。在之后的DOM2级标准中对DOM事件进行了标准化。
事件流
事件流描述的是页面中接受时间的顺序。在这点上IE和网景采用了完全相反的两种处理思路。IE采用的是事件冒泡流,网景采用的是事件捕获流。
事件冒泡(event bubbling)指从事件开始的最具体的元素接收,再逐步向上传递到最外层的节点,直到document
。如下图(来自红宝书)展示的过程,在下面的文档中:
1 |
|
如果div标签被点击,click
事件会这样依次传递:<div>
-> <body>
-> <html>
-> document
。(不同浏览器实现细节上会有不同)
事件捕获(event capturing)则认为应该从父节点开始捕获事件直到事件目标。因此,同样的上面的例子,顺序将是:document
-> <html>
-> <body>
-> <div>
。
目前很少有人使用事件捕获这种方式作为事件流。
DOM 事件流
“DOM2级标准”中规定事件流包括三个阶段,事件捕获、处于目标、时间冒泡。在实际的DOM事件流中,实际目标不会接受到事件。因此如下图展示的那样,捕获阶段停止在父目标<body>
上,之后事件发生在目标上,并作为事件冒泡的一部分。然后,冒泡阶段发生,事件传回到文档。
事件处理程序
事件处理程序指用户指定响应事件的某种动作。它们都以’on’开头。HTML元素本身都可以使用与之同名的HTML特性。
DOM0级事件处理程序
DOM0级事件处理程序就是将一个函数直接赋值给一个事件处理程序属性。使用这种方法指定的事件处理程序被认为是元素的一种方法,从而其作用域为元素本身,即this
指向引用元素。可以通过直接为事件处理程序属性赋值为null删除。
1 | var btn = document.getElementById('button'); |
所有浏览器都支持DOM0级事件处理程序。这么做的好处是可以保证浏览器兼容性,缺点是使得HTML和JavaScript紧密耦合,不利用后期维护。
DOM2级事件处理程序
伴随DOM2级标准提出,“DOM2级事件”提出了两种方法,用于绑定和解除事件处理程序:addEventListener()
和removeEventListener()
。它接受3个参数:事件名、事件处理程序对应的函数、表示捕获阶段的布尔值。
1 | var btn = document.getElementById('button'); |
使用DOM2级方法绑定事件处理程序的一个优点是,可以添加多个程序到同一个标签上。使用DOM0级方法时则会覆盖上一次的事件处理程序。IE9及以上版本都支持DOM2级事件处理程序。
由于IE事件处理程序在IE8之前,是通过类似的attachEvent()
和detachEvent()
方法。它的第一个参数是事件名(需要带上on),第二个参数是事件处理程序。通过这种方法绑定的处理程序都添加在冒泡阶段,且需要注意的是其中的this
等于window
对象。支持这种方式有IE和Opera。
因此,一个跨浏览器兼容的事件绑定和解绑应该是下面这样的:
1 | var EventUtil = { |
===
元素大小与位置
这些属性方法并不属于“DOM2级样式”,但是却经常得到使用。目前所有主流浏览器都支持这些属性。它们大多都是只读的。
偏移量
偏移量描述元素在屏幕中占用的可用空间,由其宽高决定,包括内边距、滚动条和边框(不包括外边距)。有下面4个属性:
offsetHeight
元素垂直方向上的占用空间offsetWidth
元素水平方向上的占用空间offsetLeft
元素左边框距offsetParent
元素左内边框的像素距离offsetTop
元素上边框距offsetParent
元素上内边框的像素距离
可以利用元素的offsetLeft
或offsetLeft
与其offsetParent
对应属性相加直到根元素,获取到元素相对于页面的左偏移值或上偏移值。
客户区大小
客户区大小指元素内容和内边距占据的空间大小,不包括滚动条。clientWidth
是元素内容宽度加左右内边距的宽度,clientHeight
是元素内容高度加上下内边距的高度。
可以通过对body
元素取值来获取当前浏览器视口的大小。
滚动大小
滚动大小包含滚动内容的元素大小。它有下面4个相关属性:
scrollHeight
没有滚动条时,元素内容的高度scrollWidth
没有滚动条时,元素内容的宽度scrollLeft
被隐藏在内容区域左侧的像素数,可以设置从而改变元素滚动位置scrollTop
被隐藏在内容区域上侧的像素数,可以设置从而改变元素滚动位置
scrollHeight/scrollWidth
和clientHeight/clientWidth
在不同浏览器下的表现行为并不相同,有的表示视口大小,有的表示元素内容区域大小。使用时可以取较大值。而另外两个属性scrollLeft
和scrollTop
则通常用在document
中,获取和滚动相关的属性。
确定元素大小
大多数主流浏览器为元素提供了getBoundingClientRect()
方法,返回一个对象,包含left
,right
,top
,bottom
四个属性。给出了元素相对于视口的位置。
对不支持这个方法的浏览器,可以通过偏移量的相关属性获取。
===
媒体元素
HTML5出现前,提供富媒体内容的网站多采用Flash的方式保证浏览器兼容性。HTML5新增了两个标签<audio>
和<video>
。用于方便地嵌入音频和视频内容。同时,这两个标签也提供了实现常用功能的JavaScript API。允许为媒体创建自定义控件。
1 | <video src="demo.mpg" id="foo">Video player is not available.</video> |
其中元素的src
属性指定了加载的媒体文件,还可以通过width
和height
属性指定播放器大小。controls
属性意味浏览器应该显示UI控件用于操作媒体。标签中的内容用于在不支持时显示后备内容。
因为不同浏览器支持的媒体格式集并不完全相同,可以在标签下指定一或多个<source>
元素,通过src
和type
属性指定来源和格式,视频标签下<source>
的type
中甚至可以指定codecs
表示解码器。目前现代浏览器(IE9+,对IE说的就是你)都支持这两个标签。
1 | <video id="myVideo"> |
属性
<video>
和<audio>
提供了完善的JavaScript接口,下面是一些可能会用到的它们的属性。其中很多可以直接在标签元素上设置。
autoplay
取消或设置当前autoplay
标识controls
取消或设置当前controls
标识,用于显示和隐藏浏览器内置控件currentTime
获取已经播放的秒数duration
获取媒体的总长度(秒数)ended
获取媒体是否播放完成loop
取消或设置媒体文件是否循环播放muted
取消或设置媒体文件是否静音paused
标识播放器是否暂停playbackRate
取消或设置当前播放速度readyState
标识媒体是否就绪,有0,1,2,3四种情况,表示不可用、可以播放当前帧、可以播放、加载完毕src
媒体文件来源,可重写volume
取消或设置当前音量,值为0.0到1.0
事件
这两个媒体元素还有许多事件,有的是媒体播放的结果,有的是用户操作的结果。
abort
下载中断canplay
对应着readyState
为2canplaythrough
对应着readyState
为3ended
媒体播放完毕error
下载过程网络错误pause
播放暂停play
媒体收到播放指令playing
媒体开始播放ratechange
播放速度改变seeked
移动到新位置seeking
正在移动进度条volumnchange
volumn
和muted
属性值改变waiting
播放因下载未完成暂停
在如此丰富的属性和事件的帮助下,结合play()
和pause()
方法,我们可以很容易构建一个自定义的媒体播放器。
1 | <div class="player"> |
1 | var player = document.getElementById("video"), |
最后,不是所有浏览器都支持这两个标签的所有解码器,因此有一个API来检测浏览器是否支持某种解码器。通过canPlayType()
方法,该方法接收格式/编解码器(如”audio/wav
“)字符串,返回”probably”, “maybe”或是空字符串””。像下面这样:
1 | if (audio.canPlayType("audio/mpeg")){ |