■ 注册事件
给元素添加事件,称为注册事件或者绑定事件
注册事件有以下两种方式:
- 传统方式
- 方法监听注册方式(W3C推荐)
□ 传统注册方式
利用on开头的事件,如onclick
<button onclick='alert()'></button>
btn.onclick = function(){}
特点: 注册事件的唯一性,即同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
<body>
<button>传统方式</button>
<button>方法监听注册方式</button>
<script>
var btn = document.querySelector('button');
btn[0].onclick = function(){
alert('传统方式1'); //点击传统方式按钮,不会执行该函数,它会被下面的方法覆盖
}
btn.onclick = function(){
alert('传统方式2'); //点击传统方式按钮,执行该函数,它会覆盖上面的方法
}
btn[1].addEventListener('click',function(){
alert('方法监听注册方式1'); //点击方法监听注册方式按钮,会执行该函数
})
btn[1].addEventListener('click',function(){
alert('方法监听注册方式2'); //点击方法监听注册方式按钮,会执行该函数,会先执行上面的函数,然后再执行该函数
})
</script>
</body>
□ 方法监听注册方式
特点: 同一个元素同一个事件可以注册多个监听器
按注册顺序依次执行
语法:
eventTarget.addEventListener(type,listener[,useCapture])
- type: 事件类型字符串,比如click,mouseover,注意这里不要带on
- useCapture: 可选参数,是一个布尔值,默认是false,
eventTarget.addEventListener()方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定事件时,就会执行事件处理函数
■ 删除事件(解绑事件)
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function(){
alert(11);
divs[0].onclick = null;
}
divs[1].addEventListener('click',fn) //函数调用不需要括号,移除事件需要指定方法,因此此处不能使用匿名函数
function fn(){
alert(22);
div[1].removeEventListener('click',fn);
}
</script>
</body>
■ DOM事件流
事件流描述的是从页面中接收事件的顺序
事件发生时,会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流
DOM事件流分为3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
比如,一个div添加了点击事件时,当点击了div时,DOM会先从最顶层的document开始捕获事件,如果没有找到则依次向下,html -> body,最后到div
捕获从最顶层的节点document依次向下传播,中途的html,body都会接收到点击事件,点击事件如果有处理程序,则执行,没有则向下传播
冒泡是从当前开始元素开始,从下往上传播,
代码只能使用捕获阶段或冒泡阶段其中之一,不能兼得
注意:
JS代码中只能执行捕获阶段或者冒泡阶段其中的一个阶段
onclick和attachEvent只能得到冒泡阶段
addEventListener(type,listener[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果false(或不写),表示在事件冒泡阶段调用事件处理程序
实际开发中,很少使用事件捕获,更关注事件冒泡
有些事件是没有冒泡的,比如onblur,onfocus,onmouseover,onmouseleave
例: 点击son盒子,先弹出father,再弹出son
<body>
<div class='father'>
<div class='son'>son盒子</div>
</div>
<script>
var son = document.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
},true)
var father = document.querySelector('.father');
son.addEventListener('click',function(){
alert('father');
},true)
</script>
</body>
例: 点击son盒子,先弹出son,再弹出father,最后弹出document
<body>
<div class='father'>
<div class='son'>son盒子</div>
</div>
<script>
var son = document.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
},false)
var father = document.querySelector('.father');
son.addEventListener('click',function(){
alert('father');
},false)
document.addEventListener('click',function(){
alert('document');
})
</script>
</body>
■ 事件对象
event就是一个事件对象,写到我们侦听函数的小括号里,当形参来看
事件对象只有有了事件才会存在,它是系统自动创建的,不需要传递参数
事件对象是我们事件的一系列相关数据的集合,跟事件相关的,比如鼠标点击里面就包含了鼠标相关的相关信息,鼠标坐标
如果是键盘事件,里面就包含键盘相关的信息,比如判断用户按下了哪个键
事件对象可以自己命名,一般使用e
<body>
<div>111</div>
<script>
var div = document.querySelector('div');
div.addEventListener('click',function(e){
console.log(e);
})
</script>
</body>
evenTarget.onclick = function(even){}
evenTarget.addEventListener('click',function(e){})
event对象代表事件的状态,比如键盘的状态,鼠标的位置,鼠标按钮状态等
简单理解,事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法
even是形参,系统帮助我们设定为事件对象,不需要传递实参
当我们注册事件时,event对象就会被系统自动创建,并依次传递事件监听器(事件处理函数)
□ 事件对象的常见属性和方法
e.target 返回触发事件的对象,标准
e.srcElement 返回触发事件的对象,非标准
e.type 返回事件类型,比如click,mouseover,不带on
e.cancelBubble 该属性阻止冒泡 非标准
e.returnValue 该属性阻止默认事件(默认行为)
e.preventDefault() 该属性阻止默认事件(默认行为) 标准
e.stopPropagation() 阻止冒泡 标准
e.target和this的区别
e.target: 点击了哪个元素就返回哪个元素
this:哪个元素绑定了这个点击事件,那么就返回谁
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e){
console.log(this); //返回ul,绑定了谁,this就是谁
console.log(e.target); //返回li,指向点击了那个对象,谁触发了这个事件,点击的是li e.target指向的就是li
})
</script>
</body>
□ 阻止默认行为
让链接不跳转,或者让提交按钮不提交
<body>
<a href="http://wwww.baidu.com">百度</a>
<script>
var a = document.querySelector('a');
a.addEventListener('click',function(e){
e.preventDefault(); //点击百度链接,不会发生跳转,dom标准写法
})
a.onclick = function(){
//e.preventDefault(); //传统方式
//e.returnValue; //适用于低版本ie678
return false; //也能阻止默认行为,没有兼容性问题,该写法仅限于传统方式
}
</script>
</body>
■ 阻止事件冒泡
两种方式:
标准写法:利用事件对象里面的stopPropagation()方法
<body>
<div class='father'>
<div class='son'>son盒子</div>
</div>
<script>
var son = document.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
//e.stopPropagation(); //执行该语句后,father和document就不会弹出对话框了,因为停止了冒泡,低版本的IE不支持
e.cancelBubble = true; //没有兼容性问题
},false)
var father = document.querySelector('.father');
son.addEventListener('click',function(){
alert('father'); //不点击son,直接点击father,仍然后弹出框,因为冒泡是写在son上的
},false)
document.addEventListener('click',function(){
alert('document');
})
</script>
</body>
■ 事件委托
事件委托,也称为事件代理,在JQuery里面称为事件委派
事件委托原理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
事件委托的作用
只操作了一次DOM,提高了程序的性能
<body>
<ul>
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
<li>项目4</li>
<li>项目5</li>
</ul>
<script>
var ul = dcoument.querySelector('ul');
ul.addEventListener('click',function(e){
e.target.style.backgroundColor = 'red';
})
</script>
</body>
■ 常用鼠标事件
□ 禁止选中文字
<body>
我是一段不愿分享的文字
<script>
document.addEventListener('selectstart',function(e){
e.preventDefault(); //执行该语句,页面无法选中文字
})
</script>
</body>
□ 禁止鼠标右键
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
<body>
我是一段不愿分享的文字
<script>
document.addEventListener('contextmenu',function(e){
e.preventDefault(); //执行该语句,页面无法使用鼠标右键
})
</script>
</body>
□ 鼠标对象事件
e.clientX 返回鼠标相对于浏览器窗口可视区的x坐标
e.clientY 返回鼠标相对于浏览器窗口可视区的x坐标
e.pageX 返回鼠标相对于文档页面的x坐标
e.pageY 返回鼠标相对于文档页面的y坐标
e.screenX 返回鼠标相对于电脑屏幕的x坐标
e.screenY 返回鼠标相对于电脑屏幕的y坐标
例: 获得鼠标在页面上的坐标
<head>
<style>
body {
height:3000px;
}
</style>
</head>
<body>
<script>
document.addEventListener('click',function(e){
console.log(e.clientX); //鼠标在可视区的x坐标
console.log(e.clientY); //鼠标在可视区的y坐标
console.log(e.pageX); //鼠标在页面文档的x坐标
console.log(e.pageY); //鼠标在页面文档的y坐标
})
</script>
</body>
■ 常用键盘事件
keycode: 返回该键的ascii值
注:
onkeydown和onkeyup不区分字母大小写,onkeypress区分字母大小写
在实际开发中,更多的使用keydown和keyup,它能识别所有的键,包括功能键
keypress不识别功能键,但是keycode属性区分大小写,返回不同的ascii值
<body>
<script>
document.addEventListener('keyup',function(e){
console.log(e.keycode); //按下a和A,返回都是65(对应的ascii值),keyup和keydown不区分大小写
if(e.keycode === 65){
alert('a键');
} else {
alert('不是a键');
}
})
document.addEventListener('keypress',function(e){
console.log(e.keycode); //按下a和A,分别返回97和65(对应的ascii值),keyprss区分大小写
})
</script>
</body>