JS-事件

JS-事件

  • 事件绑定
    • DOM 0级事件
      • HTML标签中事件
      • 元素.on事件
    • DOM 1级事件
      • addEventListener
        • DOM事件流
          • 事件冒泡
          • 事件捕获
          • 不冒泡事件
          • 阻止冒泡
        • passive详解
      • removeEventListener
  • 常用事件
    • 鼠标事件
    • 键盘事件
    • 其他事件
  • event对象
    • 常见属性
  • 阻止跳转
    • return false
    • preventDefault/returnValue
    • stopPropagation
  • 事件委托

事件绑定

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事件流

JS-事件_第1张图片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

JS-事件_第2张图片
图(摘自: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=false passive=true
JS-事件_第3张图片 JS-事件_第4张图片
处理器降频处理效果,实际运行只是流畅度不好 纵想丝滑

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时,父元素运行事件代码
利用事件委托可以节省内存,提高效率

你可能感兴趣的:(JS-事件)