event senior
After reading this section, you need to |
---|
Two ways to write out element registration events |
Able to say two ways to delete events |
Be able to name the three phases of the DOM event flow |
Can use the event object to complete the case of following the mouse |
Capable of encapsulating compatibility functions that prevent bubbling |
Be able to tell the principle of event delegation |
Ability to speak common mouse and keyboard events |
1. Registration event (binding event)
Adding events to elements is called registering events or binding events.
There are two ways to register events: the traditional way and the way to monitor the registration method
1.1 The difference between the traditional method and the method monitoring registration method
1.2 addEventListener event listening method (after IE9)
eventTarge.addEventListener(type,listener[,useCapture])
Create a new .html file and execute the code as follows
<!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>
</head>
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<script>
// 1.传统方式注册事件
var btns = document.querySelectorAll('button');
btns[0].onclick = function() {
alert('这是传统的注册事件1!');
}
btns[0].onclick = function() {
alert('这是传统的注册事件2!');
}
// 当鼠标点击后,后面的处理事件把前面的就会覆盖,鼠标点击按钮1时,只会出现'这是传统的注册事件2!'的弹窗,体现出唯一性。
// 2.事件监听注册事件
// (1) addEventListene 里面的事件类型是字符串 必定要加引号,而且不带on
// (2) 同一个元素,同一个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click',function() {
alert('这是方法监听注册事件1!')
})
btns[1].addEventListener('click',function() {
alert('这是方法监听注册事件2!')
})
btns[1].addEventListener('click',function() {
alert('这是方法监听注册事件3!')
})
// 当鼠标点击后,会依次弹出弹窗
</script>
</body>
</html>
The effect is as follows
1.3 attachEvent event monitoring method (before IE9)
The addEventListener method above is an event listener registration method after IE9. Before IE9, the attachEvent method was used as the event monitoring registration method, which is non-standard and not recommended
grammar:
eventTarge.attachEvent(eventNameWithOn,callback)
Create a new .html file and execute the code as follows
<!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>
</head>
<body>
<button>ie9 attachEvent</button>
<script>
// 1.attachEvent ie9之前的版本支持
var btn = document.querySelector('button');
btn.attachEvent('onclick',function() {
alert('支持ie9之前的版本');
})
</script>
</body>
</html>
The effect is as follows
1.4 Registration event compatibility solution
Summary: The addEventListener method can solve most situations, and if it cannot be solved, use the traditional method directly; the attachEvent method can be understood.
2. Delete event (unbind event)
2.1 How to delete events
Create a new .html file and execute the code as follows
<!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>
div {
width: 100px;
height: 35px;
background-color: rgb(42, 205, 210);
}
</style>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
// 1.需求:第一次点击盒子,出现弹窗,第二次点击盒子,不再出现弹窗了
var divs = document.querySelectorAll('div');
// (1) 用传统事件来做
divs[0].onclick = function() {
alert('用的是传统事件!');
divs[0].onclick = null;
}
// (2) 用addEventListener方法监听事件 ie9之后用
divs[1].addEventListener('click',fn); // 里面的fn指fn()的调用,不需要加小括号
function fn() {
alert('用的是事件监听方法');
divs[1].removeEventListener('click',fn)
}
// (3) 用attachEvent方法监听事件 ie9之前用
// divs[2].attachEvent('onclick',fn1); // 里面的fn指fn()的调用,不需要加小括号
// function fn1() {
// alert('33333');
// divs[2].detachEvent('onclick',fn1);
// }
</script>
</body>
</html>
The effect is as follows
2.2 Delete event compatibility solution
3. DOM event flow
3.1 Theoretical part
Summarize:
The sequence of event propagation is called event flow. If the process of propagating events from top to bottom is called the event capture stage, it will be in the target stage after the end, and then the event will be propagated from bottom to top. This process is called For the event bubbling phase.
3.2 Practical part
Create a new .html file and execute the code as follows
<!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>
.father {
width: 200px;
height: 200px;
margin: 200px;
background-color: rgb(109, 209, 46);
}
.son {
width: 100px;
height: 100px;
margin: 50px;
background-color: rgb(186, 34, 34);
}
</style>
</head>
<body>
<!-- .father>.son -->
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// dom 事件流 三个阶段
// 1.JS代码中只能执行捕获或者冒泡其中的一个阶段。
// 2.onclick 和 attachEvent (ie) 只能得到冒泡阶段。
// 3. 捕获阶段 如果addEventListener 第三个参数是 true, 那么则处于捕获阶段
// 执行顺序:document -> html -> body -> father -> son
// var son = document.querySelector('.son');
// son.addEventListener('click',function() {
// alert('son后弹出');
// },true);
// var father = document.querySelector('.father');
// father.addEventListener('click',function() {
// alert('father先弹出');
// },true)
// 4 冒泡阶段 如果addEventListener 第三个参数是false或者省略, 那么则处于冒泡阶段
// 执行顺序:son -> fahter -> body -> html -> document
var son = document.querySelector('.son');
son.addEventListener('click',function() {
alert('son先弹出');
},false);
var father = document.querySelector('.father');
father.addEventListener('click',function() {
alert('father后弹出');
})
document.addEventListener('click',function() {
alert('document最后弹出');
})
</script>
</body>
</html>
The effect is as follows
4. Event object
4.1 Introduction to event objects
Create a new .html file and execute the code as follows
<!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>
</head>
<body>
<div>123</div>
<script>
// 事件对象
// (1) 用传统方式
var div = document.querySelector('div');
div.onclick = function(e) {
// console.log(event);
// console.log(window.event);
// 考虑兼容性问题,用下行代码 && 和 || 是逻辑运算符
// e = e || window.event;
console.log(e);
}
// (2) 用方法监听注册方式
// div.addEventListener('click',function(event) {
// console.log(event);
// })
// 1.event 就是一个事件对象,写到我们侦听函数的 小括号里面 当形参来看
// 2.事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
// 3.事件对象 是我们事件的一系列相关数据的集合 跟事件相关的
// 比如:鼠标点击里面就包含了鼠标的相关信息,例如鼠标坐标等等
// 比如:如果是键盘事件里面就包含的键盘事件的信息 例如判断用户按下了哪个键
// 4.这个事件对象我们可以自己命名 比如event、evt、e
// 5.事件对象也有兼容性的问题 ie的678通过window.event来获取事件对象
// 兼容性写法 e = e || window.event;
</script>
</body>
</html>
The effect is as follows
The effect is as follows
4.2 Common properties and methods of event objects
Create a new .html file and execute the code as follows
<!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>
div {
width: 60px;
height: 50px;
background-color: rgb(64, 161, 127);
}
</style>
</head>
<body>
<div>123</div>
<span>456</span>
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
// 常见事件对象的属性和方法
// (1) e.target 返回的触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
var div = document.querySelector('div');
div.addEventListener('click',function(e) {
console.log(e.target);
console.log(this);
})
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e) {
// 我们给ul绑定了事件 那么this 就指向ul;点击的li,真正的是li触发了这个点击事件,因为有冒泡,所以触发
console.log(this);
// e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
console.log(e.target);
})
// 区别:
// e.target 点击了那个元素,就返回那个元素
// this 那个元素绑定了这个点击事件,那么就返回谁
// (1) 考虑兼容性时,可以如下写法
var span = document.querySelector('span');
span.onclick = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
console.log(target);
}
// (2) 了解一下,跟this有个非常相似的属性 currentTarget 但是ie浏览器的678版本不认识
</script>
</body>
</html>
The effect is as follows
4.3 Prevent default behavior
Create a new .html file and execute the following code
<!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>
div {
width: 200px;
height: 100px;
background-color: rgb(174, 72, 162);
}
</style>
</head>
<body>
<div>123</div>
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交" name="sub">
</form>
<script>
// 常见事件对象的属性和方法
// (1) e.type返回事件类型
var div = document.querySelector('div');
// 点击
div.addEventListener('click',fn); // 不写第三个参数,冒泡阶段调用事件处理程序
// 鼠标经过
div.addEventListener('mouseover',fn);
// 鼠标离开
div.addEventListener('mouseout',fn);
function fn(e) {
console.log(e.type);
}
// (2) 阻止默认行为(事件) 让链接不跳转 或者让提交按钮不提交
// (2.1) e.preventDefault
var a = addEventListener('click',function(e) {
e.preventDefault(); // dom推荐的标准写法 ie不支持
})
// (2.2) 传统的注册方式
a.onclick = function(e) {
// (2.2.1) 普通浏览器 e.preventDefault(); 方法
e.preventDefault();
// (2.2.2) 适用于低版本浏览器 ie678 returnValue 属性
e.returnValue;
// (2.2.3) 可以利用return false 也能阻止默认行为 没有兼容性问题
// 特点:return 后面的代码不执行了,而且该方式只限于传统的注册方式
return false;
alert(11); // 不会弹出,因为return后面的代码不会执行
}
</script>
</body>
</html>
The effect is as follows
5. Prevent event bubbling
5.1 Two ways to prevent event bubbling
[Hint]: Disadvantages of event bubbling
(In actual development, the capture phase doesn't matter much, we care more about the bubbling phase)
Reuse the code of **1.2 addEventListener event listening method (after IE9)**, the execution code is as follows
<!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>
.father {
width: 200px;
height: 200px;
margin: 200px;
background-color: rgb(109, 209, 46);
}
.son {
width: 100px;
height: 100px;
margin: 50px;
background-color: rgb(186, 34, 34);
}
</style>
</head>
<body>
<!-- .father>.son -->
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
var son = document.querySelector('.son');
son.addEventListener('click',function(e) {
alert('son先弹出');
e.stopPropagation(); // stop 停止 Propagation 传播
// 若考虑兼容性问题时
// e.cancelBubble = true; // cancel 取消 bubble 泡泡
},false);
var father = document.querySelector('.father');
father.addEventListener('click',function() {
alert('father后弹出');
})
document.addEventListener('click',function() {
alert('document最后弹出');
})
</script>
</body>
</html>
The effect is as follows
6. Event delegation (proxy, delegation)
[Tip]: The benefits of event bubbling
principle
Create a new .html file and execute the code as follows
<!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>
</head>
<body>
<!-- ul>li*5 -->
<ul>
<!-- shift+alt+a -->
<li>今天务必早点睡</li>
<li>今天务必早点睡</li>
<li>今天务必早点睡</li>
<li>今天务必早点睡</li>
<li>今天务必早点睡</li>
</ul>
<script>
// 事件委派的核心原理:给父节点添加侦听器,利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e) {
// alert('今晚务必早点睡');
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'green';
})
</script>
</body>
</html>
The effect is as follows
7 Commonly used mouse events
7.1 Common mouse events
Create a new .html file and execute the code as follows
<!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>
</head>
<body>
我无法右键点击复制
<script>
// (1) contextmenu 我们可以禁用右键菜单
document.addEventListener('contextmenu',function(e) {
e.preventDefault();
})
// (2) selectstart 禁止选中文字
document.addEventListener('selectstart',function(e) {
e.preventDefault();
})
</script>
</body>
</html>
The effect is as follows
7.2 Mouse event object
Tip: Determine where the mouse is clicked
Create a new .html file and execute the code as follows
<!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>
body {
height: 3000px;
}
</style>
</head>
<body>
<script>
// 鼠标点击对象 MouseEvent
document.addEventListener('click',function(e) {
console.log(e);
// (1) client 鼠标在可视区的x和y的坐标
console.log(e.clientX);
console.log(e.clientY);
// (2) page 鼠标在页面文档的x和y坐标
console.log(e.pageX);
console.log(e.pageY);
// (3) sreen 鼠标相对于电脑屏幕的x和y坐标
// e.screenX;
// e.screenY;
})
</script>
</body>
</html>
The effect is as follows
7.3 Example: Days following mouse movement
Case: find a picture, this picture has been moving with the mouse
case analysis
Create a new .html file and execute the code as follows
<!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>
/* 图片改成绝对定位 绝对定位的特点之三:绝对定位不再占用原先的位置。(脱标)*/
img {
position: absolute;
width: 100px;
height: 80px;
}
</style>
</head>
<body>
<img src="image/001.jpg" alt="">
<script>
var pic = document.querySelector('img');
// 只要一移动,就会触发事件
document.addEventListener('mousemove',function(e) {
// (1) mousemove 只要我们鼠标移动1px, 就会触发这个事件
console.log(11);
// (2) 核心原理: 每次鼠标移动,我们都会获得最新的鼠标坐标,把这个x和y坐标作为图片的top和left值
// 就可以移动图片
var x = e.pageX;
var y = e.pageY;
console.log('x坐标是' + x,'y坐标是' + y);
// (3) 千万不用忘记给left和top添加px 单位
pic.style.left = x + 'px';
pic.style.top = y + 'px';
// 鼠标和图片居中对齐 要根据图片的大小进行判断
// pic.style.left = x -50 + 'px';
// pic.style.top = y - 40 + 'px';
})
</script>
</body>
</html>
The effect is as follows
8. Common keyboard events
8.1 Common keyboard events
In addition to using the mouse to trigger the event, it can also be triggered by the keyboard.
Create a new .html file and execute the code as follows
<!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>
</head>
<body>
<script>
// 常用的键盘事件
// (1) keyup 按键弹起的时候触发
// (1.1) 传统方式
// document.onkeyup = function() {
// console.log('我弹起了');
// }
// (1.2) 监听注册方式
document.addEventListener('keyup',function() {
console.log('我弹起来了');
})
// (2) keydown 按键按下的时候触发 能识别功能键,比如:ctrl shift 左右箭头等
document.addEventListener('keydown',function() {
console.log('我按下了down');
})
// (3) keypress 按钮按下的时候触发 不能识别功能键 比如:ctrl shift 左右箭头等
document.addEventListener('keypress',function() {
console.log('我按下了press');
})
// (2) 和(3)代码交互位置,也不会影响输出结果,因为三个事件的执行顺序 keydown -> keypress -> keyup
</script>
</body>
</html>
The effect is as follows
8.2 Keyboard event object
Tip: Determine which key is pressed on the keyboard
ASCⅡ code table
Create a new .html file and execute the code as follows
<!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>
</head>
<body>
<script>
// 键盘事件对象中的keyCode属性可以得到相应键的ASCⅡ码值
// (1) 我们的keyup和keydown事件不区分字母大小写 a 和 A 得到的都是 65
// (2) 我们的keypress 事件区分字母大小写 a 97 和 A 65
// document.addEventListener('keyup',function(e) {
// // console.log(e);
// console.log('up' + e.keyCode);
// })
// document.addEventListener('keypress',function(e) {
// console.log('press' + e.keyCode);
// })
// 可以利用keyCode返回的ASCⅡ码值来判断用户按下了哪个键
document.addEventListener('keyup',function(e) {
if (e.keyCode === 65) {
alert('您按下了a键');
} else {
alert('您没有按下a键')
}
})
</script>
</body>
</html>
The effect is as follows
8.3 Case: Simulate JD button input content
Case: When we press the s key, the cursor will be located in the search box
Create a new .html file and execute the code as follows:
<!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>
</head>
<body>
<input type="text">
<script>
var search = document.querySelector('input');
document.addEventListener('keyup',function(e) {
// 先获取s键的ASCⅡ码
// console.log(e.keyCode); // 83
if (e.keyCode === 83) {
search.focus();
}
})
</script>
</body>
</html>
The effect is as follows
8.4 Case: Simulation of Jingdong express tracking number query
Requirement: When we enter content in the text box, the text box will automatically display the content in large font size.
case analysis
Create a new .html file and execute the code as follows
<!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>
* {
margin: 0;
padding: 0;
}
.search {
position: relative;
width: 178px;
margin: 100px;
}
.con {
display: none;
position: absolute;
top: -40px;
width: 171px;
border: 1px solid rgba(0, 0, 0, .2);
box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
padding: 5px 0;
font-size: 18px;
line-height: 20px;
color: #333;
}
.con::before {
content: '';
width: 0;
height: 0;
position: absolute;
top: 28px;
left: 18px;
border: 8px solid #000;
border-style: solid dashed dashed;
border-color: #fff transparent transparent;
}
</style>
</head>
<body>
<div class="search">
<div class="con"></div>
<input type="text" placeholder="请输入你的快递单号" class="jd">
</div>
<script>
//快递单号输入内容时,上面的大号字体盒子(con)显示(这里面的字号更大)
//表单检测用户输入,给表单添加键盘事件
//同时把快递单号里面的值(value)获取过来赋值给con盒子(innerText)作为内容
//如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
// 表单里的值是通过value获取的,而div只能通过innerText或者innerHTML获取
jd_input.addEventListener('keyup', function() {
if (this.value == '') {
con.style.display = 'none';
} else {
con.style.display = 'block';
con.innerText = this.value;
}
})
//失去焦点,隐藏con盒子
jd_input.addEventListener('blur', function() {
con.style.display = 'none';
})
//获得焦点,显示con盒子
jd_input.addEventListener('focus', function() {
if (this.value !== '') {
con.style.display = 'block';
}
})
</script>
</body>
</html>
The effect is as follows