事件对象
当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,在事件对象中封装了当前事件相关的一切信息。
比如: 鼠标的坐标、键盘哪个按键被按下、鼠标滚轮滚动的方向。。。在 IE8 中,响应函数被触发时,浏览器不会传递事件对象,在 IE8 及以下的浏览器中,是将事件对象作为 window 对象的属性保存的
JavaScript
window.onload = function () {
//当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标
//获取两个div
var areaDiv = document.getElementById('areaDiv')
var showMsg = document.getElementById('showMsg')
areaDiv.onmousemove = function (event) {
//在IE8中,响应函数被触发时,浏览器不会传递事件对象,在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的
if (!event) {
event = window.event
}
//解决事件对象的兼容性问题
event = event || window.event
var x = event.clientX
var y = event.clientY
//在showMsg中显示鼠标的坐标
showMsg.innerHTML = 'x = ' + x + ' , y = ' + y
}
}
事件的冒泡(Bubble)
- 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发。
- 在开发中大部分情况下冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象 cancelBubble 来取消冒泡。
javascript
var s1 = document.getElementById('s1')
s1.onclick = function(event) {
event = event || window.event
//取消冒泡
//可以将事件对象的cancelBubble设置为true,即可取消冒泡
event.cancelBubble = true
}
事件的委派
- 指将事件统一给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理后代元素的事件。
- 通过事件的冒泡,我们可以将一个事件绑定给多个元素共同的祖先元素,即可应用到多个元素上,即使有的元素是后来添加的,此时点击后代元素会通过冒泡触发该祖先元素的事件。
- 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能。但是注意此时该祖先元素下的其他后代元素也会触发该事件,故需要通过 if 判断来筛选出我们期望触发该事件的元素。
- target:event 中的 target 表示的是触发事件的对象。
javascript
ul.onclick = function(event) {
event = event || window.event
//如果触发事件的对象是我们期望的元素,则执行,否则不执行
if (event.target.className == 'link') {
//执行事件。。。
}
}
事件的绑定
- 使用
对象.事件 = 函数
的形式绑定响应函数,它只能同时为一个元素的一个事件绑定一个响应函数,不能为一个元素绑定多个响应函数,否则后添加的会把前面的覆盖掉。 - 如果需要为一个元素同时绑定多个事件,我们可以通过
addEventListener()
方法为元素绑定响应函数。
javascript
/*
addEventListener()
1. 通过这个方法可以为元素绑定响应函数。
2. 参数:
1. 事件的字符串,不用on(直接写click)。
2. 回调函数,当事件触发时该函数会被调用。
3. 是否在捕获阶段触发事件,需要一个布尔值,一般都传false。
3. 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,这样当事件被触发时,响应函数将会按照函数的绑定顺序从上到下执行。
4. 这个方法在IE8及以下的浏览器不支持,如需兼容IE8及以下,可以使用attachEvent()来绑定事件。
*/
btn01.addEventListener(
'click',
function() {
alert(1)
},
false
)
btn02.addEventListener(
'click',
function() {
alert(2)
},
false
)
/*
attachEvent()
1. 通过这个方法也可以为元素绑定响应函数。
2. 参数:
1. 事件的字符串,要写on。
2. 回调函数,当事件触发时该函数会被调用。
3. 这个方法也可以同时为一个事件绑定多个处理函数,不同的是它是后绑定的先执行,执行顺序和addEventListener()相反。
4. addEventListener()中的this指向的是绑定事件的对象(btn01),attachEvent()中的this,指向的是window,需要统一两个方法的this。
*/
btn01.attachEvent('onclick', function() {
alert(1)
})
/*
解决兼容性问题,定义一个函数,来用为指定元素绑定响应函数。
参数:
1. obj 要绑定事件的对象
2. eventStr 事件的字符串(不要on)
3. callback 回调函数
*/
function bind(obj, eventStr, callback) {
if (obj.addEventListener) {
//大部分浏览器兼容的方式
obj.addEventListener(eventStr, callback, false)
} else {
//this是谁,由调用方式决定 callback.call(obj)
//IE8及以下
obj.attachEvent('on' + eventStr, function() {
//添加匿名函数的作用是此时浏览器会默认调用匿名函数function(){}(),之后再在匿名函数调用call()方法
//如果直接写callback.call(obj),浏览器在调用时会变成callback.call(obj)(),会报错。
//在匿名函数中调用回调函数,在IE8中this会变成window,必须使用匿名函数才会变成obj
callback.call(obj)
})
}
}
事件的传播
关于事件的传播,网景公司和微软公司有不同的理解。
微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就是事件在冒泡阶段执行。
网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该向触发当前元素的最外层的祖先元素的事件,然后再向内传播给后代元素直到当前元素为止,也就是在事件的捕获阶段执行。
W3C 综合了两个公司的方案,将事件传播分成了三个阶段
text1. 捕获阶段 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件。 2. 目标阶段 事件捕获到目标元素,捕获结束开始在目标元素上触发事件。 3. 冒泡阶段 事件从目标元素向它的祖先元素传递。,依次触发祖先元素上的事件。
如果希望在捕获阶段就触发事件,可以将
addEventListener()
的第三个参数设置为 true。一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是 false。在 IE8 及以下的浏览器中没有捕获阶段(没有
addEventListener()
函数)。
拖拽事件
拖拽的流程
- onmousedown:当鼠标在被拖拽元素上按下左键时,开始拖拽。
- onmousemove:当鼠标移动时被拖拽元素跟随鼠标移动。
- onmouseup:当鼠标松开时,被拖拽元素固定在当前位置。
JavaScript//拖拽box1元素 var box1 = document.getElementById("box1"); //为box1绑定一个鼠标按下事件 //如果要拖拽图片,需要对图片设置绝对定位,position:absolute; drag(box1); //提取一个专门用来拖拽的函数 //参数: obj 开启拖拽的元素 function drag(obj){ //①为obj绑定一个鼠标按下事件 obj.onmousedown = function(event){ //取消浏览器默认行为,兼容IE8,为box1设置捕获所有鼠标按下的事件,防止chrome报错要添加if判断 //if(box1.setCapture){ // box1.setCapture(); // } obj.setCapture && obj.setCapture();//利用&&与运算的短路作简化判断,if判断的简写,返回第一个假或最后一个真。 event = event || windows.event; //div的偏移量 鼠标.clientX - 元素.offsetLeft //div的偏移量 鼠标.clientY - 元素.offsetTop var ol = event.clientX - obj.offsetLeft; //这里的event.clientX 和 event.clientY是鼠标点击时的值,这个值是定值 var ot = event.client - obj.offsetTop; //②为document绑定一个onmousemove事件 document.onmousemove = function(event){ event = event || windows.event; //与onmousedown中的event范围不一样,不是同一个event,一个是box1的event,一个是document的event //获取鼠标的坐标 var left = event.clientX - ol; //这里的event.clientX 和 event.clientY是鼠标移动时的值,是个变量 var top = event.clientY - ot; //修改box1的位置 obj.style.left = left + "px"; obj.style.top = top + "px"; }; //③为document元素绑定一个鼠标松开事件 document.onmouseup = function(){ //取消document的onmousemove事件 document.onmousemove = null; //取消document的onmouseup事件 document.onmouseup = null; //取消box1对事件的捕获 obj.releaseCapture && obj.releaseCapture(); //防止chrome报错,判断是否存在该方法,存在则调用 } //取消浏览器默认行为 return false; }; }
取消浏览器默认行为
- 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,此时会导致拖拽功能的异常。这个是浏览器提供的默认行为,如果不希望发生这个行为,可通过 return false 来取消默认行为。
- 但是这个方法对 IE8 不起作用。如果要兼容 IE8 需要对拖拽元素使用
setCapture()
方法
text
setCapture()
1. 当调用于一个元素的setCapture()以后,这个元素将会把下一次所有的其他元素(包括点击刷新浏览器窗口甚至点击桌面)鼠标按下相关事件捕获到自身上.
2. 使用releaseCapture()取消元素对事件的捕获。
3. setCapture()方法只有IE支持,但是在火狐中调用不会报错,而在chrome中调用则会报错。
鼠标滚轮滚动事件
onmousewheel
- 该事件会在鼠标滚轮滚动时触发,但是火狐不支持该属性。
- 在火狐中需要使用 DOMMousecroll 来绑定滚动事件,且该事件需要通过
addEventListener()
函数来绑定。
event.wheelDelta(在 IE 是 window.event.wheelDelta)
- 可以获取鼠标滚轮滚动的方向。
- 向上滚动返回 120;向下滚动返回 -120(每滚动一次返回一次)
- wheelDelta 这个值一般不看大小,只看正负。
- wheelDelta 这个属性火狐也不支持,在火狐中需要使用 event.detail 来获取滚动的方向,且向上返回 -3 ,向下返回 3。
JavaScript//在IE和chrome中绑定滚轮事件 box1.onmousewheel = function(){ //事件处理。。。 }; //在火狐中绑定滚轮事件 //bind()函数在上面可查 bind(box1,"DOMMouseScroll",function(){ //事件处理。。。 }); //进行事件提取简化,方案一 function fun(){ //事件处理。。。 }; box1.onmousewheel = fun; bind(box1,"DOMouseScroll",fun); //进一步提取简化,方案二 box1.onmousewheel = function(event){ //当鼠标滚轮向下滚动时,box1变长,向上滚动变短 event = event || window.event; //判断滚轮滚动方向,兼容火狐 if(event.wheelDelta > 0 || event.detail < 0){ //向上滚动box变短 box1.style.height = box1.clientHeight - 10 + "px"; }else{ //向下滚动box变长 box1.style.height = box1.clientHeight + 10 + "px"; } //取消默认滚轮行为,兼容IE、火狐、chrome event.preventDefault && event.preventDefault(); //如果存在该方法则调用 return false; }; bind(box1."DOMMouseScroll",box1.mousewheel); //直接将box1.mousewheel作为回调函数调用
取消浏览器默认滚动行为
- 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,这是浏览器的默认行为,如果不希望发生默认行为,需要使用 return false 取消默认行为。
- 但是在火狐浏览器中,使用的是
addEventListener()
方法绑定的响应函数(DOMMouseScroll),该方法取消默认行为时不能使用 return false。addEventListener()
方法需要调用event.preventDefault()
方法取消默认行为。 - 但是在 IE8 中不支持
event.preventDefault()
方法,直接调用会报错。故如需使用需要添加 if 判断或与运算短路。
键盘事件
onkeydown
- 键盘按键被按下时触发该事件
- 对于 onkeydown 事件来说,如果一直按着某个按键不松开,则此时事件会一直被触发。
- 当 onkeydown 连续触发(按下键盘按键不放)时,第一次和第二次之间会间隔时间稍微长一点,之后触发时间会非常短。这种设计是为了防止用户误操作的发生(防止按下一个 a 键立马出现多个 a)。
- 在文本框中输入内容属于 onkeydown 的默认行为,如果在 onkeydown 事件中取消默认行为,则输入的内容将不会出现在文本框中(但此时依然会触发 onkeydown 事件)。
onkeyup
- 键盘按键松开时触发该事件,且默认只会触发一次。
键盘事件一般都会绑定给一些可以获取到焦点的对象或者是 document。
javascript//给document绑定键盘事件 document.onkeydown = function(event) { //输出按键编码 event = event || window.event console.log(event.keyCode) //判断Y键是否被按下 if (event.keyCode === 89) { //Y被按下事件。。。 使用 === 全等防止浏览器自动类型转换 } //判断y和ctrl键是否同时被按下 if (event.keyCode === 89 && event.ctrlkey) { //同时被按下事件。。。 } } //给获取焦点对象input绑定键盘事件 var input = document.getElementsByTagName('input')[0] input.onkeydown = function() { console.log('按键被按下,除了数字都会显示在文本框中') if (event.keyCode >= 48 && event.keyCode <= 57) { return false //禁止输入数字,数字按键被按下了,但是不会显示在文本框 } }
keyCode
- 通过 event.keyCode 来获取按键的编码由此来判断是哪个按键被按下。
- 除了 keyCode,事件对象中还提供了以下几个属性:
- altkey 判断 alt 键是否被按下
- ctrlkey 判断 ctrl 键是否被按下
- shiftkey 判断 shift 键是否被按下
- 如果按下则返回 true,否则返回 false。
- 数字 0~9 键的 keyCode 码是 48~57 。