事件
概念
- 事件就是用户和游览器交互的瞬间。
- 事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水。当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了。
事件的三要素
-
事件源:绑定在谁身上的事件。
-
事件类型:绑定一个什么事件。
常见的事件类型
//鼠标事件 都要在前面加on才能触发 click 点击事件 dblclick 双击事件 mousemove 鼠标移入 mouseover 鼠标移入 mouseout 鼠标移出 mouseleave 鼠标进去离开后 mousedown 鼠标按下 与click类似 mouseup 鼠标抬起 按下抬起后触发 mouseenter 鼠标移入 contextmenu 右键单击事件 mousewheel 鼠标滚轮事件 //键盘事件 keydown 鼠标按下触发 keypress 鼠标按下按着不放时触发 keyup 鼠标按下抬起后触发 //游览器事件 load 程序加载完毕触发 resize 窗口改变 scroll 滚动条滚动 //表单事件 专门给form,input,textarea,select标签使用的 focus 聚焦事件 blur 失焦事件 change 改变事件 input 输入事件 submit 提交事件(绑定给form标签) reset 重置事件(绑定给form标签) //移动端触摸事件 touchstart 触摸开始(手放在屏幕上的时候) touchmove 触摸移动(手在屏幕上移动) touchend 触摸结束(手离开屏幕的时候) // 其他事件 transitionend 过渡动画结束 需要特殊的绑定方式 animationend 帧动画结束 需要特殊的绑定方式 selectstart 开始框选文本
-
事件处理程序:当行为发生的时候, 要执行哪一个函数
事件对象
概念:在每一个事件触发的时候都应该有一些描述性的信息,当我们把这个信息放到一个对象里面,我们就管这个对象叫事件对象
document.onclick = function(eve){ var e = eve || window.event;//兼容ie8 console.log(e); }
三大家族
document.onclik = function(eve){ var e = eve || window; //offset 自己的,用与获取元素的尺寸 e.offsetWidth e.offsetHeight 获取对象自身的宽度和高度,包括内容,边框和内边距,即: offsetWidth = width + border + padding e.offsetX 事件触发后,距离当前最近元素的内部左边的偏移量 e.offsetY 事件触发后,距离当前最近元素的内容上边的偏移量 e.offsetLeft e.offsetTop 距离最近一级有定位的父级盒子左边和上边的距离 父级盒子一定要有定位,没有定位则最终以body为准 offsetLeft和offsetTop从从父标签的padding开始计算,不包括border。即:从子盒 子边框到定位父盒子边框的距离。 //client e.clientX:鼠标距离可视区域左侧距离(event调用) e.clientY:鼠标距离可视区域上侧距离(event调用) e.clientWidth: 获取对象自身的宽度,包括内容,内边距.不包含边框 e.clientHeight: 获取对象自身的高度,包括内容,内边距.不包含边框 e.clientTop和e.clientLeft: 元素的border(边框) //scroll scrollHeight: 内容高,不含border scrollWidth: 内容宽,不含border scrollTop:游览器向上或向左滚走的距离 scrollLeft: scrollIntoView();//内容停留在内容区底部 //怪异模式:页面中没有doctype声明 需要使用 document.body.scrollTop //标准模式:页面中有doctype声明 document.body.scrollTop值 为0 需要使用:document.documentElement.scrollTop //e.pageX:当前坐标距离浏览器左边的距离 + 浏览器向左滚走的距离 //e.pageY:当前坐标距离浏览器上边的距离 + 浏览器向上滚走的距离 //e.screenX:了解,距离设备屏幕左边的距离 //e.screenY:了解。距离设备屏幕顶端的距离 }
事件对象的属性
1.鼠标事件属性
-
button属性,用在onmousedown事件上使用
-
用来判断按下了鼠标上的哪个键
-
ie8: 1 4 0(左键 滚轮键 右键)
-
高版本浏览器(现代浏览器):0 1 2
兼容处理 function getButton(eve){ //判断是什么浏览器 if(eve){//eve存在表示是现代浏览器 return eve.button; }else{//ie8下运行的 var but = window.event.button; switch(but){ case 1: return 0; case 4: return 1; case 2: return 2; } } }
2.键盘对象属性
**keycode:**获取键码属性
2.1可以用来判断按下了哪一个键
2.2每一个键都有对应的ASCII码
document.onkeydown = function(eve){
var e = eve || event;
console.log(e.keyCode);
//在onkeydown中获取的是大写状态下的ASCII,与键盘本身的大小写输入状态无关
}
//在onkeyup中获取的是大写状态下的ASCII,与键盘本身的大小写输入状态无关
//在onkeypress中获取ASCII与键盘本身的大小写输入状态有关
//onkeypress事件,在键盘的除了空格和回车键以外,其它功能键不会被触发
document.onkeydown = function(eve){
var e = eve || event;
console.log(e.ctrlKey);//当键盘按下ctrl键时,返回true
if(e.ctrlKey && e.altKey){//判断是否按下了ctrl和alt的组合键
alert("按下了");
}
var code = e.keyCode || e.which || e.charCode;//兼容写法
//是否是按下了ctrl和回车键
if(e.ctrlKey && code === 13){
alert("发送了");
}
}
document.onkeypress = function(eve){
var e = eve || event;
var code = e.keyCode || e.which || e.charCode;
//虽然onkeypress不能触发功能键
//但在onkeypress中设置ctrl和回车的组合键可以触发
//这里code的值为10
if(e.ctrlKey && code === 10){
alert("发送了");
}
}
事件流
- 事件流描述的是从页面中接收事件的顺序。
- DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。
事件两种模式
1.冒泡事件
- 由内向外,子元素向父元素触发
//冒泡事件的阻止
but.onclick = function(eve){
var e = eve || event;
//需要阻止冒泡
e.stopPropagation();//方法在ie8下不支持
e.cancelBubble = true;//ie8下使用
· //兼容写法
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
}
2.事件捕获
- 由外向内,父元素向子元素触发
- 事件捕获,只有在addEventListener中才可以实现捕获的设置
- 默认事件是冒泡
形成条件:多个元素之间有父子关系,多个元素注册了同一事件
3.阻止事件默认行为
<a href="http://www.baidu.com">百度</a>
var a = document.getElementsByTagName("a")[0];
a.onclick = function(eve){
var e = eve || event;
e.preventDefault();//阻止事件的默认行为 ie8不支持
e.returnValue = false;//ie8使用
!!e.preventDefault ? e.preventDefault() : e.returnValue = false;//兼容
console.log("点击了");
}
//调用函数的兼容ie8阻止事件 的默认行为
function preventDef(e){
!!e.preventDefault ? e.preventDefault() : e.returnValue = false;
}
4.事件的三个阶段
1.捕获阶段
2.目标阶段
3.冒泡阶段
4.如果捕获和冒泡同时存在,则会先触发捕获事件,后冒泡。
事件的监听
- 当同一个元素,绑定了同一事件,后面的事件会覆盖前面的事件,如何解决?就需要使用事件监听。
- 事件监听可以给同一事件绑定多次。
写法
//第一种
box.addEventListener("click",fn);
function fn(){
console.log("点击2");
}
//第二种
box.addEventListener("click",function(){
console.log("点击1");
})
事件监听的兼容
//ie8下使用
box.attachEvent("onclick",function(){
console.log("ok")
})
事件监听的移除
//传统事件绑定的移除
//obj.事件 = null;
but.onclick = function(){
console.log("1")
}
setTimeout(function(){
but.onclick = null;
},1000);
//移除监听的事件
but.addEventListener("click",callBack);
but.attachEvent("onclick",callBack);
function callBack(){//移除的前提是要将事件处理程序提取出来,变成 命名函数
console.log("ok");
}
setTimeout(function()){
but.removeEventListener("click",callBack);//高版本游览器
but.detachEvent("onclick",callBack);//attachEvent的移除 ie8
},100);
事件的委托
- 将事件统一绑定给元素共同的祖先元素(后代元素事件触发时,通过冒泡,通过祖先元素的响应函数来处理事件)
- 事件的委托利用了冒泡,通过委派可以减少事件的绑定次数,提高程序的性能。
- 事件对象中使用target来表示触发的事件对象,使用它对触发事件的元素进行判断。
var ul = document.getElementsByTagName("ul")[0];
ul.onclick = function(eve){
var e = eve || event;
e.target//:属性保存了所有的子元素节点,
console.log(e.target);//鼠标触发的是哪个子元素,target返回的就是哪个元素
if(e.target.nodeName === "LI"){//因为nodeName返回的是大写
console.log(e.target.innerHTML)
}
}
//兼容ie8
var target = e.target || e.srcElement;
事件委托的好处
- 可以节约内存
- 提高程序的性能
- 可以动态给元素元素添加绑定事件。
缺点:容易被子级元素阻止