事件
JavaScript和HTML的交互是通过事件实现的。JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件。如果JavaScript关注特定类型事件,那么它可以注册当这类事件发生时要调用的句柄
- 事件是某个行为或者触发,比如点击、鼠标移动
- 当用户点击鼠标时
- 当网页已加载时
- 当图像已加载时
- 当鼠标移动到元素上时
- 当用户触发按键时...
事件无处不在,在javascript中,我们如何去观察事件呢?
事件流
事件流描述的是从页面中接收事件的顺序,比如有两个嵌套的div,点击了内层的div,这时候是内层的div先触发click事件还是外层先触发?
说明: 例如这里的button,我点击的时候,是先触发'wrap',还是先触发button
目前主要有三种模型
- IE的事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的元素
事件捕获:不太具体的节点更早接收事件,而最具体的元素最后接收事件,和事件冒泡相反
DOM事件流:DOM2级事件规定事件流包括三个阶段,事件捕获阶段,处于目标阶段(到达目标的那个事件),事件冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡阶段
这种分歧在日常生活中也很常见,举个例子,某个地方出了抢劫事件,我们有多种处理方式
- 村里先发现,报告给乡里,乡里报告到县城,县城报告给市里。。。。
- 市里先知道这事儿,然后交代给县城怎么处理,县城交给到乡里处理,乡里交给村里处理
Opera、Firefox、Chrome、Safari都支持DOM事件流,IE不支持事件流,只支持事件冒泡
如有以下html
Test Page
·Click Here
点击div区域
事件冒泡模型 | 事件捕获模型 | DOM事件流 |
事件处理程序
我们也称之为事件侦听器(listener),事件就是用户或浏览器自身执行的某种动作。比如click、load、mouseover等,都是事件类型(俗称事件名称),而响应某个事件的方法就叫做事件处理程序或者事件监听器
也就是我们需要提前定义好某些事件发生了该怎么处理,这个过程叫做绑定事件处理程序,了解了这些,我们看看如何给元素添加事件处理程序
HTML内联方式
元素支持的每个事件都可以使用一个相应事件处理程序同名的HTML属性指定。这个属性的值应该是可以执行的JavaScript代码,我们可以为一个button添加click
事件处理程序(这种方式在早期使用,因为还没有样式与操作分离的概念)
在HTML事件处理程序中可以包含要执行的具体动作,也可以调用在页面其它地方定义的脚本,刚才的例子可以写成这样
在HTML中指定事件处理程序书写很方便,但是有两个缺点。
存在加载顺序问题,如果事件处理程序在html代码之后加载,用户可能在事件处理程序还未加载完成时就点击按钮之类的触发事件,存在时间差问题
这样书写html代码和JavaScript代码紧密耦合,维护不方便
JavaScript指定事件处理程序
通过JavaScript指定事件处理程序就是把一个方法赋值给一个元素的事件处理程序属性。
每个元素都有自己的事件处理程序属性,这些属性名称通常为小写,如onclick
等,将这些属性的值设置为一个函数,就可以指定事件处理程序,如下
这样处理,事件处理程序被认为是元素的方法,事件处理程序在元素的作用域下运行,this就是当前元素,所以点击button结果是:btnClick
这样还有一个好处,我们可以删除事件处理程序,只需把元素的onclick属性赋为null即可
DOM2事件处理程序
DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作:
- addEventListener
- removeEventListener
所有的DOM节点都包含这两个方法,并且它们都接受三个参数:
- 事件类型
- 事件处理方法
- 布尔参数,如果是true表示在捕获阶段调用事件处理程序,如果是false,则是在事件冒泡阶段处理
刚才的例子我们可以这样写
上面代码为button添加了click事件的处理程序,在冒泡阶段触发,与上一种方法一样,这个程序也是在元素的作用域下运行,不过有一个好处,我们可以为click事件添加多个处理程序
这样两个事件处理程序会在用户点击button后按照添加顺序依次执行。
通过addEventListener添加的事件处理程序只能通过removeEventListener移除,移除时参数与添加的时候相同,这就意味着刚才我们添加的匿名函数无法移除,因为匿名函数虽然方法体一样,但是句柄却不相同,所以当我们有移除事件处理程序的时候可以这样写
事件冒泡
container
box
target
通过this得知监听的元素
阻止默认事件
baidu
事件代理
box1
box2
box3
鼠标事件
onmousedown, onmouseup, onclick, ondbclick, onmousewheel, onmousemove, onmouseover, onmouseout
相关细节
-
对象上的style属性
-
获取元素的真实样式
说明:style属性只能获取到html标签的内联样式,但在这里,文字颜色为蓝色,这个样式被写进了style标签内,style熟悉无法获取到元素的真实样式,所以,需要通过getComputedStyle来获取真实的样式,这是一个全局属性
-
样式与行为分离
说明:对于图片中的1写法,如果我们需要在事件发生时,对一个元素添加多个样式,那就意味着我们要写许多个style属性进去,这样代码太复杂;前面提过,样式与行为分离,这样一来,我们可以先将对应的样式写好并添加一个class,然后通过js往这个元素上加一个class,就可以实现效果
mouseover、mouseout、mouseenter、mouseleave
input相关事件
-
输入框focus、blur
focus状态下输出1
blur状态下输出2 -
展现输入框内容并且转换为大写
-
通过keyboardEvent查看用户所按按键
-
change 当输入框内容发生变化时
输入内容时,内容在改变,但并未执行函数
输入完,点击页面,执行函数,控制台输出内容。那么change和blur有什么区别呢?对于blur,只要输入框失焦了,都会去执行函数;而对于change,可以理解为两个过程,首先输入框失焦,然后判断输入框的内容和之前是否发生了改变,只有发生了改变,才会执行函数。 -
form表单的提交时间
需求:例如,做一个登录或注册的页面,填完表单后,提交并进行数据的验证
-
scroll事件
load事件(图片加载完成)
对于一些图片,我们不知道它的尺寸,只有在图片加载完成时,才能通过js去访问到,所以这时可以使用load事件
触摸事件
ontouchstart, ontouchend, ontouchmove
键盘事件:
onkeydown, onkeyup, onkeypress
页面相关事件:
onload, onmove(浏览器窗口被移动时触发), onresize(浏览器的窗口大小被改变时触发), onscroll(滚动条位置发生变化时触发)
表单相关事件
onblur(元素失去焦点时触发), onchange(元素失去焦点且元素内容发生改变时触发), onfocus(元素获得焦点时触发), onreset(表单中reset属性被激活时触发), onsubmit(表单被提交时触发);oninput(在input元素内容修改后立即被触发,兼容IE9+)
编辑事件
onbeforecopy:当页面当前的被选择内容将要复制到浏览者系统的剪贴板前触发此事件;
onbeforecut:当页面中的一部分或者全部的内容将被移离当前页面[剪贴]并移动到浏览者的系统剪贴板时触发此事件;
onbeforeeditfocus:当前元素将要进入编辑状态;
onbeforepaste:内容将要从浏览者的系统剪贴板传送[粘贴]到页面中时触发此事件;
onbeforeupdate:当浏览者粘贴系统剪贴板中的内容时通知目标对象;
oncontextmenu:当浏览者按下鼠标右键出现菜单时或者通过键盘的按键触发页面菜单时触发的事件;
oncopy:当页面当前的被选择内容被复制后触发此事件;
oncut:当页面当前的被选择内容被剪切时触发此事件;
onlosecapture:当元素失去鼠标移动所形成的选择焦点时触发此事件;
onpaste:当内容被粘贴时触发此事件;
onselect:当文本内容被选择时的事件;
onselectstart:当文本内容选择将开始发生时触发的事件;
拖动事件
ondrag:当某个对象被拖动时触发此事件 [活动事件];
ondragdrop:一个外部对象被鼠标拖进当前窗口时触发;
ondragend:当鼠标拖动结束时触发此事件;
ondragenter:当对象被鼠标拖动的对象进入其容器范围内时触发此事件;
ondragleave:当对象被鼠标拖动的对象离开其容器范围内时触发此事件;
ondragover:当某被拖动的对象在另一对象容器范围内拖动时触发此事件;
ondragstart:当某对象将被拖动时触发此事件;
ondrop:在一个拖动过程中,释放鼠标键时触发此事件;
自定义事件
var EventCenter = {
on: function(type, handler){
document.addEventListener(type, handler)
},
fire: function(type, data){
return document.dispatchEvent(new CustomEvent(type, {
detail: data
}))
}
}
EventCenter.on('hello', function(e){
console.log(e.detail)
})
EventCenter.fire('hello', '你好')
参考
- http://www.dengzhr.com
- MDN