一、注册事件和删除事件
1.注册事件的两种方式
<button>传统注册方式</button>
<button>方法监听注册事件</button>
第一种:传统注册事件也就是我们之前常用的
var btn = document.querySelectorAll('button');
//传统注册事件
btn[0].onclick = function () {
alert('hi');
}
第二种:方法监听注册事件
语法是下面这样,注意事件类型onclick一定要去掉on,里面类型是字符串,一定要加引号
btn[1].addEventListener('click', function () {
alert('aoaoao');
})
二者的区别:传统方法同一个元素只能添加一个监听器,如果添加多个会被后面的覆盖;第二种方法同一个元素,同一个事件可以添加多个监听器(function里面的东西就叫监听器),按顺序依次执行。
2.删除事件的两种方式
比如有两个div
<div>传统注册方式</div>
<div>方法监听注册事件</div>
第一种:传统注册事件删除事件用this.onclick = null;
var div = document.querySelectorAll('div');
div[0].onclick = function () {
alert('11');
//删除事件实现点击一次就失效
this.onclick = null;
}
第二种:方法监听注册事件删除事件用this.removeEventListener(‘click’, fn);
其中fn是函数的名字,这里注意不要写fn(),语法规定只写函数名字,不调用。
点击一次之后就删除事件
div[1].addEventListener('click', fn);
function fn() {
alert('22');
div[1].removeEventListener('click', fn);
}
二、DOM事件流
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流
事件捕获阶段→处于目标阶段→事件冒泡阶段
代码验证:
上面讲的方法监听注册事件,实际上还有第三个参数,这个参数就是决定是事件捕获还是事件冒泡
比如我来两个div:
<div class="father">
<div class="son">son</div>
</div>
事件捕获:
如果第三个参数是true,那么就是事件捕获,从上往下捕获,这个时候我如果点son,会先弹出来father,再弹出来son,如果我点father,只弹出来father(看上面的图,因为点击father只捕获到father)
var father = document.querySelector('.father');
var son = document.querySelector('.son');
//给父亲添加点击事件,true表示事件捕获
father.addEventListener('click', function () {
alert('father');
}, true);
//点击son,结果弹出来father,再弹出来son
son.addEventListener('click', function () {
alert('son');
}, true);
事件冒泡:
如果第三个参数是false或者不写,那么就是事件冒泡,从下往上冒泡,这个时候我如果点son,会先弹出来son,再弹出来father。点击father,只弹father,为什么不是先son再father?因为和捕获不一样,冒泡是从当前执行的地方往上冒,不会去找儿子。
var father = document.querySelector('.father');
var son = document.querySelector('.son');
//给父亲添加点击事件,true表示事件捕获,false或者不写表示事件冒泡
father.addEventListener('click', function () {
alert('father');
}, false);
//点击son,结果弹出来son,再弹出来father
son.addEventListener('click', function () {
alert('son');
}, false);
一般冒泡用的多一点,如果父节点true捕获,子节点不管是false冒泡还是true捕获,那么点击子节点都是先father再son。这是因为事件流的顺序是事件捕获阶段→处于目标阶段→事件冒泡阶段,捕获阶段先执行,如果father是捕获就先弹father,这时候son其实就是目标阶段,son是冒泡还是捕获已经不重要了。而如果father是冒泡,那么捕获阶段走过来不会执行father,走完son再往上走,才能找到father,所以会先son再father。所以主要要看father是什么(这段话可以再理解理解)
三、事件对象
1.什么是事件对象?
点击鼠标,是一个事件,然后log输出就会输出下面这些信息:
可以看看下面的解释:
2.事件对象常用的属性和方法
(1)e.target和this的区别
target属性和this的区别是什么呢?
event.target返回的是触发事件的对象(元素),而this返回的是绑定事件的对象(元素)
.target是点了谁就返回谁,比如下面这个我绑定的是ul,那我点击li触发了ul,那么.target返回的就是li。而this则返回的是我绑定的ul
(2)event.preventDefault() 阻止默认行为
(3)event.stopPropagation() 阻止事件冒泡
四、事件委托(代理、委派)(面试重点理解)
原理:不在每个子节点单独设置事件监听器(函数),而是在其父节点上设置事件监听器,然后利用事件冒泡来通过子节点影响父节点
比如有这样的ul和小li
<ul>
<li>惊起一滩鸥鹭</li>
<li>惊起一滩鸥鹭</li>
<li>惊起一滩鸥鹭</li>
<li>惊起一滩鸥鹭</li>
<li>惊起一滩鸥鹭</li>
</ul>
如果想点击每个li就变色,那么按照以前的方式,我们要循环给每个li添加注册事件,但这样非常麻烦,而且如果添加的太多会影响页面效率。那么我们可以给li的父节点ul添加点击事件,然后当我们点击li时,事件会冒泡到ul上,从而触发ul的事件监听器,这时候如果我们想对li操作,可以利用事件对象的target属性找到它
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
e.target.style.backgroundColor = 'pink';
})
五、常用的键盘鼠标事件
1. 鼠标事件
(1) 禁止鼠标右键菜单:
(2)禁止选中文字:
(3).鼠标事件对象
(4)案例:跟随鼠标的天使
先分析一波:
放代码:
<style>
img {
position: absolute;
}
</style>
</head>
<body>
<img src="ts.png" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function(e){
//1. 只要我们移动1像素 就会触发这个事件
// console.log(1);
//2. 把最新的x y坐标作为我们图片的top left坐标
var x = e.pageX;
var y = e.pageY;//一定记得XY大写!
console.log('x坐标是'+x,'y坐标是'+y);
pic.style.left = x - 20 + 'px';//-20是为了让鼠标在图片的正中间
pic.style.top = y - 20 + 'px';//一定记得拼接单位px 否则没用
});
</script>
2. 键盘事件对象
(1)常用的键盘事件
三个事件的执行顺序:keydown→keypress→keyup
(2)键盘事件对象
现在这个已经废掉了。
弹幕说可以用.key 但是不晓得我用.key也没用
(3)案例:按下s键获取文本框焦点(模仿京东)
看下思路:
记得用keyup,用keydown会吧s也填进去
<input type="text">
<script>
var search = document.querySelector('input');
document.addEventListener('keyup', function (e) {
if (e.key == 83) {
search.focus();
}
})
</script>
(4)案例:京东快递单号查询
看下思路:
这里注意要用keyup,键盘抬起触发,要是用keydown或者keypress会有bug,比如keydown的话是按下先执行监听器,然后才填内容,也就是会有一个小小的延迟。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
position: relative;
margin: 100px 100px;
}
.big {
position: absolute;
display: none;
top: -62px;
height: 50px;
border: 1px solid black;
font-size: 30px;
}
.big::before {
/* 当父元素不需要占有位置时,子绝父绝也是可以的 */
position: absolute;
left: 10px;
bottom: -21px;
content: '';
display: inline-block;
width: 0;
height: 0;
border: 10px solid transparent;
border-top-color: black;
}
</style>
</head>
<body>
<div class="box">
<div class="big"></div>
<input type="text" placeholder='请输入你的快递单号:'>
</div>
<script>
var big = document.querySelector('.big');
var input = document.querySelector('input');
input.addEventListener('keyup', function (e) {
if (input.value != '') {
big.innerHTML = this.value;
big.style.display = 'block';
} else {
big.style.display = 'none';
}
})
//离开焦点隐藏
input.addEventListener('blur', function () {
big.style.display = 'none';
})
//获得焦点时,如果文本框内容不为空,就显示放大
input.addEventListener('focus', function () {
if (input.value != '') {
big.style.display = 'block';
}
})
</script>
</body>
</html>