JavaScript事件基础、事件原理、事件区别与兼容
事件基础
//侦听事件(侦听的类型,事件回调函数) 侦听类型必须字符串
document.addEventListener(“abc”,abcHandler);
//创建事件
var evt=new Event(“abc”);
//把事件向document抛发
document.dispatchEvent(evt);
//抛发的对象必须和侦听对象是同一个对象
//所有继承了EventTarget的对象都可以进行事件侦听和抛发
function abcHandler(e){
// 当侦听收到事件后会执行回调函数,函数中有且仅有一个参数
// 这个参数就是创建的事件对象
console.log(e);
}
//先侦听后抛发
解耦
var obj={
a:1,
init:function(){
document.addEventListener("obj1Event",this.b);
},
b:function(e){
console.log(e.c);
var evt=new Event("objEvent");
evt.a=1;
document.dispatchEvent(evt);
}
}
var obj1={
c:2,
init:function(){
document.addEventListener("objEvent",this.d);
var evt=new Event("obj1Event");
evt.c=2;
document.dispatchEvent(evt);
},
d:function(e){
console.log(e.a);
}
}
obj.init();
obj1.init();
事件原理
事件侦听对象.addEventListener(事件类型,事件触发回调函数,是否捕获时触发事件=false)
true为捕获阶段触发
事件侦听对象.addEventListener(事件类型,事件触发回调函数,{once:true})//once是true表示该事件仅执行一次,就被销毁
e.type事件侦听的类型
e.bubbles事件是否冒泡
e.stopPropagation();阻止冒泡
默认状态下事件触发是冒泡阶段
捕获 目标 冒泡
外 达到目标 内
| |
内 外
默认创建的事件不会自动冒泡
创建事件的第一个参数是事件的type
第二个参数是事件初始化对象,对象中属性bublles是否冒泡,true冒泡,默认是false
var evt=new Event(“abc”,{bubbles:true});
div1.dispatchEvent(evt);
事件委托:把子元素的事件委托给父元素侦听,事件委托
事件委托案例:列表点击
<ul>
<li>北京
<ul class="ul1">
<li>昌平
<ul class="ul1">
<li>老牛湾</li>
<li>沙河</li>
<li>回龙观</li>
<li>霍营</li>
</ul>
</li>
<li>海淀</li>
<li>朝阳</li>
<li>东城</li>
<li>西城</li>
</ul>
</li>
<li>陕西
<ul class="ul1">
<li>西安</li>
<li>咸阳
<ul class="ul1">
<li>淳化</li>
<li>三原</li>
<li>旬邑</li>
<li>泾阳</li>
</ul>
</li>
<li>宝鸡</li>
<li>延安</li>
</ul>
</li>
<li>河北</li>
<li>河南</li>
<li>山西</li>
</ul>
var ul=document.querySelector("ul");
ul.addEventListener("click",clickHandler);
// 把子元素的事件委托给父元素侦听,事件委托
function clickHandler(e){
// console.log(this); this就是事件侦听的对象
// console.log(e.target,e.srcElement);//点击事件的目标元素,这两个是相同的
// console.log(e.currentTarget===this)//e.currentTarget就是this也就是事件侦听对象
// 这里不需要取消冒泡
if(e.target.constructor!==HTMLLIElement)return;
// if(e.target.nodeName!=="LI") return;
e.target.bool=!e.target.bool;
if(e.target.firstElementChild && e.target.firstElementChild.constructor===HTMLUListElement){
if(e.target.bool){
e.target.firstElementChild.className="ul1 ul2";
}else{
e.target.firstElementChild.className="ul1";
}
}
事件的区别和兼容
onclick事件
1、使用onclick时具有覆盖性
2、行内的onclick如果没有后续的onclick则会执行,否则会被覆盖
3、行内的onclick(需要在函数名后加括号)执行的函数不是回调函数,而是直接使用函数执行
4、如果是IE6以下,没有e这个参数,所以无法获取这个事件对象5、行内事件中,因为不传递e这个参数,因此也无法获取事件对象6、当无法获取e对象时可以通过e=e||window.event获取,(事件兼容方式)用于onclick写法
on事件和addEvevtListener区别:
1、on事件支持任何浏览器兼容,addEventListener只支持IE8及以上浏览器
2、on事件,实际上是针对DOM对象有一个固定的属性。例如onclick,一般会赋值给这个属性一个匿名函数,当再次赋值时会覆盖上次的函数。addEventListener事件会使用回调函数添加,可以设置多个事件对象函数,不会覆盖
3、on事件多用匿名函数,开发时很容易产生回调地狱,但是使用addEventListener多使用命名函数有效控制回调地狱的产生
4、on事件不支持捕获阶段事件,addEventListener支持捕获阶段事件,还支持once冒泡(IE8以上阻止冒泡e.stopPropagation;e.concelBubble取消冒泡兼容写法)
5、删除事件方式不同:addEventListener使用removeEventListener,on事件用div.οnclick=null删除事件
6、因为on事件都是系统自动为DOM对象添加的事件类型,因此固定,addEventListener支持自定义事件,可以自己抛发事件接收
回调地狱案例:
实现按顺序点击才能打印:
on产生回调地狱
var div0=document.querySelector(".div0");
var div1=document.querySelector(".div1");
var div2=document.querySelector(".div2");
var div3=document.querySelector(".div3");
var div4=document.querySelector(".div4");
div1.onclick=function(){
div2.onclick=function(){
div3.onclick=function(){
div4.onclick=function(){
console.log("aaa");
}
}
}
}
addEventListener方法控制:
div1.addEventListener("click",clickHandler);
function clickHandler(e){
switch(this){
case div1:
div2.addEventListener("click",clickHandler);
break;
case div2:
div3.addEventListener("click",clickHandler);
break;
case div3:
div4.addEventListener("click",clickHandler);
break;
case div4:
console.log("aaaa");
}
}
attachEvent和addEvevtListener:
element.attachEvent(‘on开头的事件名’,事件函数名)添加事件,只支持IE11以下浏览器,其他浏览器不支持,不支持捕获冒泡
element.detachEvent(‘on开头的事件名’,事件函数名)移除事件,不支持事件抛发
attachEvent和addEvevtListener兼容写法
function addEvent(elem, type, calLback, bool){
if(bool==undefined) bool=false;
if(elem. addEventListener){
elem. addEventListener(type, callback, bool);
}elset
elem. attachEvent("on"+type, calLback);
}