JavaScript——DOM事件流以及常用事件

127 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情

事件流

1.什么是事件流

html中的标签都是相互嵌套的,我们可以将元素想象成一个盒子装一个盒子,document是最外面的大盒子。 当你单击一个div时,同时你也单击了div的父元素,甚至整个页面。 比如给页面中的一个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。

事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程,我们称之为事件流。 事件流描述的是页面元素接收事件的顺序。

image-20210901221526.jpeg

2.事件流的三个阶段

1.事件捕获阶段:事件开始时,由DOM最顶层节点开始,然后逐级向下,一直传播到最具体的元素接收的过程。 2.处于目标阶段:事件到达最具体的这个元素时。 3.事件冒泡阶段:事件开始时,由最具体的元素接收,然后逐级向上,一直传播到DOM最顶层节点的过程。

image-20210901221527.jpeg

W3C规定事件流遵循先捕获再冒泡的顺序。例如:我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点(最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。

image-20210901221528.jpeg

3.事件流的使用

1.实际开发中很少使用事件捕获,我们更关注事件冒泡。 2.事件冒泡有时候会带来麻烦,有时候又会帮助很巧妙的做某些事件。 3.JS代码中只能执行捕获或者冒泡其中的一个阶段。(注:可以写两段代码分别执行捕获和冒泡阶段)

4.有些事件只能得到冒泡阶段,比如:onclick。(一般用on开头的都没有捕获阶段)

<div class="father">大盒子
    <div class="son">小盒子</div>
</div>
​
var son = document.querySelector('.son');
son.onclick = function() {
    alert('您点击了小盒子');
}
var father = document.querySelector('.father');
father.onclick = function() {
    alert('您点击了大盒子');
}
var body = document.body;
body.onclick = function() {
    alert('您点击了body');
}
var html = document.documentElement;
html.onclick = function() {
    alert('您点击了html');
}
document.onclick = function() {
    alert('您点击了document');
}
注:即使调整以上代码的顺序,依然会按照冒泡的顺序执行,而不是按照代码的顺序。

5.有些事件是没有冒泡的,比如:onfocus、onblur、onmouseenter、onmouseleave。

<div class="father">大盒子
    <div class="son">小盒子</div>
    <input type="text" name="" id="" value="小文本框" class="son" />
</div>
​
var son2 = document.querySelector('.son').nextElementSibling;
son2.onfocus = function() {
    alert('您的鼠标聚焦到了小文本框');
}
var father = document.querySelector('.father');
father.onfocus = function() {
    alert('您的鼠标聚焦到了大盒子');
}
var body = document.body;
body.onfocus = function() {
    alert('您的鼠标聚焦到了body');
}
var html = document.documentElement;
html.onfocus = function() {
    alert('您的鼠标聚焦到了html');
}
document.onfocus = function() {
    alert('您的鼠标聚焦到了document');
}

6.addEventListener 的第三个参数为 true,则为捕获阶段,为false或者省略,则为冒泡阶段。

image-20210901221529.jpeg

<div class="father">大盒子
    <div class="son">小盒子</div>
</div>
​
var son = document.querySelector('.son');
son.addEventListener('click', function() {
    alert('您点击了小盒子');
}, true);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
    alert('您点击了大盒子');
}, true);
var body = document.body;
body.addEventListener('click', function() {
    alert('您点击了body');
}, true);
var html = document.documentElement;
html.addEventListener('click', function() {
    alert('您点击了html');
}, true);
document.addEventListener('click', function() {
    alert('您点击了document');
}, true);
注:将addEventListener的第三个参数true改为false或者去掉,就是冒泡阶段。

7.attachEvent 只能得到冒泡阶段。

<div class="father">大盒子
    <div class="son">小盒子</div>
</div>
​
var son = document.querySelector('.son');
son.attachEvent('onclick', function() {
    alert('您点击了小盒子');
});
var father = document.querySelector('.father');
father.attachEvent('onclick', function() {
    alert('您点击了大盒子');
});
var body = document.body;
body.attachEvent('onclick', function() {
    alert('您点击了body');
});
var html = document.documentElement;
html.attachEvent('onclick', function() {
    alert('您点击了html');
});
document.attachEvent('onclick', function() {
    alert('您点击了document');
});

6.常用事件

事件描述
onclick用户点击 HTML 元素。即鼠标点击左键触发。
onload浏览器已完成页面的加载。即浏览器完成页面的加之后自动触发该事件。 最常用于 元素中,其他支持onload的标签还有:,,<img>, , 。 (写在body标签中;在JavaScript代码中绑定;以监听方式绑定("load"))。
onchangeHTML 元素改变。比如用户修改了表单的内容之后触发该事件。 onchange属性可以使用于: , 和 。
onfocus获得鼠标焦点触发。就是当光标落在文本框中时发生的事件。
onblur失去鼠标焦点触发。就是当光标离开文本框中时发生的事件。
onmouseenter鼠标进入元素瞬间触发,只触发一次。在元素的子元素之间相互切换不会触发。
onmouseleave鼠标离开元素瞬间触发,只触发一次。在元素的子元素之间相互切换不会触发。
onmouseover鼠标进入元素瞬间触发,会触发多次。在元素的子元素之间相互切换会不断触发。
onmouseout鼠标离开元素瞬间触发,会触发多次。在元素的子元素之间相互切换会不断触发。
onkeypress用户按下键盘按键后触发。功能键(箭头、符号、F1-F12、Ctrl、Shift等)不会触发。
onkeydown用户按下键盘按键后触发。所有按键皆会触发。
onkeyup用户松开键盘按键后触发。所有按键皆会触发。

onclick案例

上面已经接触很多了,此处不再重复。

1.onload案例

<!-- 1.以属性的形式写在元素里面 -->
<body onload="onload()">
    <h1>var str = "https://www.baidu.com?name=张三";</h1>
</body> 
<body>
    <h1>var str = "https://www.baidu.com?name=张三";</h1>
</body>
​
function onloadFunc() {
    document.querySelector('h1').style.color = 'red';
}
/* 2.在JavaScript代码中绑定 */
document.body.onload = onloadFunc;
//window.onload = onloadFunc;亦可,不建议对onload以外的事件这么使用。
/* 3.在JavaScript代码中以监听的方式绑定 */
document.body.addEventListener('load', onloadFunc);
//window.addEventListener("load", onloadFunc);亦可,不建议对load以外的事件这么使用。

2.onchange案例

<!-- 1.以属性的形式写在元素里面 -->
输入您的姓名: <input type="text" id="textId" onchange="upperCase(this.id)" />
<br>
输入您的履历: <input type="text" id="textId2" />
​
function upperCase(a) {
    var b = document.getElementById(a).value;
    document.getElementById(a).value = b.toUpperCase();
}
function upperCase2() {
    var b = document.getElementById('textId2').value;
    document.getElementById('textId2').value = b.toUpperCase();
}
/* 2.在JavaScript代码中绑定 */
document.getElementById('textId2').onchange = upperCase2;
//window.onchange=upperCase2;亦可,但是只对第一个input起作用,建议不要这么用。
/* 3.在JavaScript代码中以监听的方式绑定 */
document.getElementById('textId2').addEventListener("change", upperCase2);
//window.addEventListener("change", upperCase2);亦可,但是只对第一个input起作用,建议不要这么用。

3.onfocus/onblur案例

<!-- 1.以属性的形式写在元素里面 -->
输入您的姓名: <input type="text" id="textId" onfocus="upperCase(this.id)" onblur="lowerCase(this.id)" />
​
function upperCase(a) {
    var b = document.getElementById(a).value;
    document.getElementById(a).value = b.toUpperCase();
}
function lowerCase(a) {
    var b = document.getElementById(a).value;
    document.getElementById(a).value = b.toLowerCase();
}

4.onmouseenter/onmouseleave案例

<div class="father" onmouseenter="enter()" onmouseleave="leave()">大盒子
    <div class="son">小盒子</div>
    <input type="text" name="" id="" value="小文本框" class="son" />
</div>
​
function enter() {
    console.log('您的鼠标进入了大盒子');
    var r = parseInt(Math.random() * 256);
    var g = parseInt(Math.random() * 256);
    var b = parseInt(Math.random() * 256);
    var rgb = "rgb(" + r + "," + g + "," + b + ")";//随机生成的颜色  rgb(2,3,4)
    document.querySelector('.father').style.backgroundColor = rgb;
    // document.querySelector('.father').style.backgroundColor='red';
}
function leave() {
    console.log('您的鼠标离开了大盒子');
    document.querySelector('.father').style.backgroundColor='green';
}

5.onmouseover/onmouseout案例

<div class="father" onmouseover="over()" onmouseout="out()">大盒子
    <div class="son">小盒子</div>
    <input type="text" name="" id="" value="小文本框" class="son" />
</div>
​
function over() {
    console.log('您的鼠标进入了大盒子');
    var r = parseInt(Math.random() * 256);
    var g = parseInt(Math.random() * 256);
    var b = parseInt(Math.random() * 256);
    var rgb = "rgb(" + r + "," + g + "," + b + ")"; //随机生成的颜色
    document.querySelector('.father').style.backgroundColor = rgb;
    // document.querySelector('.father').style.backgroundColor='red';
}
function out() {
    console.log('您的鼠标离开了大盒子');
    document.querySelector('.father').style.backgroundColor='green';
}

6.onkeypress/onkeydown/onkeyup案例

<h1>测试onkeyup、onkeydown和onkeypress的区别</h1>
<input type="text" id="test1" placeholder="测试onkeypress" onkeypress="onkeypressTest()"/>
<br><br>
<input type="text" id="test2" placeholder="测试onkeydown" onkeydown="onkeydownTest()" />
<br><br>
<input type="text" id="test3" placeholder="测试onkeyup" onkeyup="onkeyupTest()" />
<br><br>
<input type="text" id="test4" placeholder="测试onkeyup、onkeydown和onkeypress" onkeypress="onkeypressTest()" onkeydown="onkeydownTest()" onkeyup="onkeyupTest()" />
​
function onkeyupTest() {
    alert("我是onkeyup");
    console.log("我是onkeyup");
}
function onkeydownTest() {
    alert("我是onkeydown");
    console.log("我是onkeydown");
}
function onkeypressTest() {
    alert("我是onkeypress");
    console.log("我是onkeypress");
}
​

说明: 1.onkeydown事件最先执行,其次onkeypress,最后onkeyup;onkeydown和onkeypress会影响onkeyup的执行。 2.三个事件同时存在时,都是alert的话,只会弹出2个alert,up事件的alert不会弹出。 3.onkeydown、onkeypress事件响应时输入的字符并没有被系统接受,而响应onkeyup时,输入流已经被系统接受。 4.由于onkeydown比onkeypress先执行,onkeydown触发时输入流正要进入系统,即onkeydown事件一完,输入流就  进入了系统,无法改变。所以通过onkeydown事件可以改变用户是按了哪个键;而onkeypress事件则是在输入流进入  系统后触发的,但输入流暂未被系统处理,此时已经不能改变输入流了;onkeyup则是输入流被系统处理后发生的。