加载中

JS-事件

事件绑定

DOM 0级事件

有2个:HTML标签中事件元素.on事件=函数

HTML标签中事件

<a href="#" onclick="open()">打开</a>

元素.on事件

var btn = document.getElementById("btn1");
btn.onclick=function(){
	console.log("sj1");
}
btn.onclick=function(){		//会覆盖原来的函数
	console.log("sj2");
}

这种方法只能触发一个函数,若要触发多个可以用addEventListener

DOM 1级事件

只有一个:addEventListener()
IE 678不支持

addEventListener

addEventListener可以给一个对象添加多个触发函数

//以前只支持
addEventListener(type,listener[,useCapture])
//2017年年底 DOM规范做了修订,第三个参数可以是对象值了
addEventListener(type,listener[,options])
//参数如下,默认都为 false
options{
  capture:false,  //相等于以前的第三个参数(useCapture) 
  passive:false,  //是否取消检测 preventDefault,详细内容看 "passive详解" 小节
  once:false  //是否只能触发一次(触发一次后removeEventListener)
}
  • 参数1:String类型,事件名
  • 参数2:执行的函数
  • 参数3(第一种):是否在捕获阶段触发执行,默认false(冒泡时触发)

参数3解析:一个事件触发的流程是 触发事件 -> 捕获过程 -> 冒泡过程

DOM事件流

d3包含在d2,d2包含在d1;点击d3,产生以下结果:

事件冒泡
//若都是冒泡阶段触发,则执行顺序为:d3,d2,d1(从里向外冒泡)
d1.addEventListener('click',say);
d2.addEventListener('click',say);
d3.addEventListener('click',say);
事件捕获
//若都是捕获阶段触发,则执行顺序为:d1,d2,d3(从外向里)
d1.addEventListener('click',say,true);
d2.addEventListener('click',say,true);
d3.addEventListener('click',say,true);

混合:

//由内向外依次检测是否有捕获过程执行的,然后冒泡
//若一部分是冒泡,一部分是捕获,则先从外向里执行捕获,再从里向外执行冒泡
d1.addEventListener('click',say,true);
d2.addEventListener('click',say);
d3.addEventListener('click',say);
检测d2是否捕获执行
检测d1是否捕获执行
执行d1
执行d3
执行d2

在这里插入图片描述
图(摘自:qianguyihao)

不冒泡事件

有:blur、focus、load、unload、onmouseenter、onmouseleave

例:

d1.addEventListener('mouseenter',say);
d2.addEventListener('mouseenter',say);
d3.addEventListener('mouseenter',say);
document.body.addEventListener('mouseenter',say);
document.addEventListener('mouseenter',say);

鼠标移入body,结果为:body
鼠标移入d1,结果为:d1
鼠标移入d2,结果为:d2

鼠标直接移入d3,结果为:body,d1,d2,d3

document的事件没有被触发,因为该事件不会冒泡
直接移入d3产生了"类似冒泡",是因为其他元素真实产生了事件,然后按事件捕获由外由内执行
若是click事件,则无论任何时候,都会产生冒泡
总结:不冒泡的事件,例如load时每个元素如果都冒泡的话就没有意义了

阻止冒泡

IE,谷歌,火狐:event.stopPropagation()
IE,谷歌:event.cancelBubble = true
例:

//点击d3,结果只有d3,没有冒泡到父级
d1.addEventListener('click',say);
d2.addEventListener('click',say);
d3.addEventListener('click',say);

function say(){
	//兼容性代码
	event=event | window.event;
	if(event.stopPropagation){
		event.stopPropagation();
	}else{
		event.cancelBubble=true}
	......
}

passive详解

移动设备上有一个touchmove事件,在手指滑动屏幕时触发,系统默认事件是根据滑动方向滚动页面

//如下代码,会阻止默认事件,造成页面无法滚动
document.addEventListener("touchmove",function(){
  event.preventDefault();  //阻止本次事件
});
//取消检测preventDefault,此时屏幕可以正常滚动
document.addEventListener("touchmove",function(){
  event.preventDefault();
},{passive:true});  //不检测 preventDefault,使其失灵

其实passive最大的作用是减少运算,增加页面滚动流畅度(看对比图)

//默认情况下,系统会一直检测preventDefault是否存在,会占用cpu资源
//可以用passive关闭对它的检测,减少运算
document.addEventListener("touchmove",function(){},{passive:true});
/*还可用于:
    mousewheel(鼠标滚轮事件)
    ...
*/
passive=falsepassive=true
处理器降频处理效果,实际运行只是流畅度不好纵想丝滑

removeEventListener

removeEventListener(event,function,<useCapture>);

常用事件

addEventListener中使用不用加on,DOM 0级事件要加on

鼠标事件

事件名解释
onclick单击
ondblclick双击(不要漏了l)
onmousedown鼠标按下
onmouseup鼠标松开
onmousemove每次移动都触发
onmouseenter当次进入时仅触发一次
onmouseleave当次离开时仅触发一次
onmouseover当次进入时触发一次,若触碰到子元素并再次回到该元素(并不出界)时会再次触发
onmouseout离开,进入子元素,进入子元素并回到当前元素,进入子元素的子元素的子…都会触发
oncontextmenu在当前元素上右击打开菜单时触发(只要弹出菜单就触发,不是必须右键)

键盘事件

事件名解释
onkeydown按下任意键(按下不松开会一直触发)
onkeyup松开任意键
onkeypress按下任意键(按下不松开会一直触发)(和keydown相比,按下altctrlf1-f10等键时keypress不会触发)

其他事件

事件名解释
onload一般用于window.onload,页面加载完后执行某些代码
onchange例如文本框内容改变时触发

event对象

不同浏览器写法(例如window.event/event)和值(例如button属性)不同,可能存在兼容性问题
在触发一个事件时,会产生一个event对象,如下:

d1.addEventListener('mousedown',say);
function say(){
	console.log(event);	//产生event对象
}
/*
function say(e){console.log(e);}	//ok
function say(e){console.log(event);}	//ok
*/

常见属性

属性名解释
timeStamp触发时间(ms)
target事件源
button鼠标按键 谷歌,IE9+,火狐(左0,中1,右2) IE678(左1,中4,右2)
pageX/pageY光标在页面中的位置(px),例如页面左上角pageX=0,pageY=0
clientX/clientY光标在页面中相对于可视区域(滚动条外的区域不算)的位置(px)

阻止跳转

return false

会阻止事件冒泡,所以不推荐

<a href="https://www.baidu.com">跳转</a>
var a=document.getElementsByTagName("a")[0];
a.onclick=function(){  //注意只能用oncliK. addEventListener无效
  return false;  //此时点击标签也不会跳转
};
/* 
!注意 return false会阻止事件冒泡,所以父对象不会响应
document.οnclick=function(){
  console.log("a的父对象document接收到了冒泡事件");
}
*/

preventDefault/returnValue

这两个方法/属性不会阻止事件冒泡

a.onclick=function(){
  if(event && event.preventDefault){	//IE6789
    event.preventDefault();
  }else{
    window.event.returnValue=false;	//IE10+,其他
  }
};

stopPropagation

仅阻止事件冒泡,当前事件仍然响应

a.onclick=function(){
  event.stopPropagation();
};

事件委托

有一个列表:

<ul id="ul">
	<li id="li1">li1</li>
	<li id="li2">li2</li>
	<li id="li3">li3</li>
</ul>

要实现点击li,输出id,正常情况下要分别添加3个li的事件,实际上可以利用冒泡原理,在父元素ul中添加li的事件来实现
实现代码:

ul.addEventListener('click',say);
function say(){
	if(event.target.nodeName.toUpperCase()=="LI"){	//判断事件源节点名是不是LI
		console.log(event.target.id);	//如果是就输出事件源的id
	}
}

点击li,虽然li没添加事件,但冒泡到父元素ul时,父元素运行事件代码
利用事件委托可以节省内存,提高效率

posted @ 2019-09-08 15:19  jialeYang  阅读(53)  评论(0编辑  收藏  举报