DOM
Hello World
<body>
<button id="btn"> </button>
<!-- 使用DOM控制页面 -->
<script>
let btn = document.getElementById('btn');
btn.innerHTML = "Hello World";
</script>
</body>
DOM(Document Object Model):
- DOM是
Web Api
中的一部分即文档对象模型- DOM把网页中所有的内容转化为对象,然后在对其进行操作来控制页
获取文档节点(document)
文档节点(document)对象:
- document代表整个网页
document对象的原型链:
HTMLDocument --> Document --> Node --> EventTarget --> Object.prototype --> null
- 凡是在原型链上存在的对象的属性和方法都可以通过Document去调用
Document的部分属性:
实例属性:
document.documentElement
--> 获取html根元素document.head
--> 获取head元素document.title
--> 获取title元素document.body
--> 获取body元素document.links
– >获取页面中所有的超链接
获取元素节点(element)
<body>
<div><button id="btn">按钮</button></div>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<div>我是div
<div class="d">dddd</div></div>
<span>ssss</span>
</div>
<div>我是div</div>
<div>我是div</div>
<script>
//根据获取id元素节点对象
const btn = document.getElementById('btn');
//根据获取class元素节点对象
const s1 = document.getElementsByClassName('s1');
//根据获取标签名元素节点对象
const divs = document.getElementsByTagName('div');
//根据选择器来获取元素节点对象
const s2 = document.querySelectorAll('div');
const btn2 = document.querySelector('#btn');
const btn3 = document.querySelector('div #btn');
//创建一个元素节点对象
const c = document.createElement('h2');
</script>
</body>
元素节点(element)对象:
- 在网页中每一个标签都是一个元素节点
- 我们可以通过
document
来获取已有的节点和创建没有的节点通过
doucment
来获取已有的元素节点:
document.getElementById()
:根据id获取一个元素节点对象document.getElementsByClassName()
:根据元素的Class属性来获取一组元素节点对象,返回一个类数组对象,且可以实时刷新document.getElementsByTagName()
:根据标签名来获取一组元素节点对象,返回一个类数组对象,且能实时刷新document.getElementsByName()
:根据name属性来获取一组元素节点对象,返回一个类数组对象,且能实时刷新,一般用于获取表单的元素节点对象document.querySelectorAll()
:根据选择器来获取一组元素节点对象,返回一个类数组,但不能实时刷新document.querySelector()
:根据选择器获取一个元素的节点对象,但会第一个符合条件的元素节点对象不能实时刷新**通过
document
**来创建一个新的元素节点对象:
document.createElement()
:创建一个新的元素节点对象(但不会直接插入到网页中)
属性和方法
<body>
<div id="box1">
我是div
<span class="s1">我是div内的span</span>
<span class="s1">我是div内的span</span>
</div>
<span class="s1">div里的span</span>
<script>
//获取class属性为s1的元素节点
const s = document.getElementsByClassName('s1');
//获取id属性为div的元素节点
const box = document.getElementById('box1');
//通过div这个元素节点对象来获取其他的节点
//获取box下的class属性为s1的元素节点
const boxs = box.getElementsByClassName('s1');
//获取box下的所有子节点(包括文本节点:文字, 注释, 换行)
const s1 = box.childNodes;
//获取box下的所有元素节点
const s2 = box.children;
</script>
</body>
div的原型链:
HTMLDivElement --> HTMLElement --> Element --> Node --> EventTarget --> Object.prototype --> null
通过元素节点对象来获取其他节点:
element.childNodes
获取当期元素下的所有子节点(包括文本节点:文字,注释,换行)element.children
获取当前元素下的所有元素节点element.firstElementChild
获取当前元素下的第一个子节点element.lastElementChild
获取当前元素下的最后一个子节点element.nextElementSibling
获取当前元素的下一个兄弟元素element.previousElementSibling
获取当前元素的前一个兄弟元素element.parentNode
获取当前元素的父节点element.tagName
获取当前元素的标签名
获取文本节点(text)
<body>
<div></div>
<div id="box1">
我是div
<span class="s1" style="display: none">我是div内的span</span>
<span class="s1">我是div内的span</span>
</div>
<span class="s1">div外的span</span>
<script>
const box = document.getElementById('box1');
console.log(box.textContent);
console.log(box.innerText);
console.log(box.innerHTML)
box.innerText = '<li>我是li标签</li>';
box.textContent = '<li>我是li标签</li>';
box.innerHTML = '<li>我是li标签</li>';
</script>
</body>
在DOM中所有文本内容都是文本节点对象,可以通过元素来获取其中的文本节点对象,但是我们通常不这么做,一般会直接通过元素去修改其中的文本
通过元素节点对象直接修改文本的三个属性:
element.textContent
获取或修改元素中的文本内容,只获取标签里的内容,且不会考虑css样式element.innerText
获取或修改元素中的文本内容,获取内容时会考虑css样式(读取,计算css样式,触发网页重排),字符串中有标签时,会自动对标签进行转义(<li>--> <li>
)element.innerHTML
获取或修改元素中的html代码,可以直接向元素中添加html代码,通过innerHTML向网页插入元素时,有被xss注入的风险
获取属性节点(Attr)
<body>
<input class="in" type="text" value="张三" name="username" disabled>
<div class="box">
我是div
<a class="box-a" href="">我是div里的a标签</a>
</div>
<script>
//获取元素节点对象
const n = document.getElementsByName('username')[0];
const n1 = document.querySelector('.box');
const n2 = document.querySelector('.box a');
console.log(n);
console.log(n1);
console.log(n2);
//通过元素节点对象来对属性节点进行操作
// 方式一
// 读取
console.log(n.value, n.type, n.name, n.className, n.disabled);
// 修改
console.log(n.value = '李四', n.className = 'xg', n.disabled = false, n.type = 'button');
n1.style = 'color: red';
n2.href = 'https://baidu.com'
// 方式二
// 读取
console.log(n.getAttribute('type'), n.getAttribute('value'), n.getAttribute('name'), n.getAttribute('class'));
// 修改
console.log(n.setAttribute('type', 'text'), n.setAttribute('value', '瑞克'), n.setAttribute('name', 'modi'), n.setAttribute('class', 'll'));
n1.setAttribute('style', 'background: yellowgreen');
n2.setAttribute('style', 'text-decoration: none');
// 删除
console.log(n.removeAttribute('disabled'));
</script>
</body>
属性节点(Attr):
- 在DOM中也是一个对象,通常不需要获取对象而是直接通过元素直接对其进行各种操作
操作属性节点:
方式一:
- 读取: 元素.属性名(注意class属性需要使用className来读取),读取一个布尔值时返回true或false
- 修改:元素.属性名 = 属性值
方式二:
- 读取:
元素.getAttribute(属性名)
- 修改:
元素.setAttribute(属性名, 属性值)
- 删除:
元素.removeAttribute(属性名)
事件(event)
<body>
<!-- 方式1 -->
<button id="btn" onclick="alert('hello')" >点击事件</button>
<script>
//方式2:为元素指定的属性绑定事件的回调函数
//获取元素节点对象
const btn = document.querySelector('#btn');
console.log(btn);
btn.onclick = function() {
document.querySelector('body').style = 'background: #bfa';
}
// 方式3: 通过元素的addEventListener()方法来绑定事件
btn.addEventListener('click', function() {
// document.write('sh');
document.querySelector('body').innerHTML = '<div>增加</div>'
});
</script>
</body>
事件(event):
- 事件就是用户和页面之间的交互行为(例如:点击按钮,鼠标移动,敲击键盘等)
- 可以通过为事件绑定响应函数(回调函数),来完成和用户之间的交互
绑定响应函数的方式:
- 可以直接在元素的属性中设置
- 可以通过为元素的指定的属性设置回调函数的形式来绑定事件(一个事件只能绑定一个响应函数)
- 可以通过元素的
addEventListener()
方法来绑定事件
文档的加载
<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 {
background-color: rgba(77, 119, 68, 0.47);
/* text-align: center;
margin-top: 300px */
}
</style>
<script>
// 3.js代码编写在DOMContentLoaded回调函数中
document.addEventListener('DOMContentLoaded', function(){
const btn = document.querySelector('#btn');
});
// 4.js代码编写在window.onload回调函数中
window.onload = function() {
const btn = document.querySelector('#btn');
}
</script>
<!--2. 以defer的形式引入外部js文件 -->
<script defer src="./01helloModule.js"></script>
</head>
<body>
<button id="btn">点击事件</button>
<!--1. js代码编写在body的底部(最快最有效) -->
<script>
const btn = document.querySelector('#btn');
alert(btn);
</script>
<script src="./01helloModule.js"></script>
</body>
文档的加载:
- 网页的加载时自上向下进行的,如果把js代码编写在网页的上边,会导致js代码在执行时,网页还没加载完毕,会出现无法获取DOM对象的情况
js代码编写位置:
- 将js标签编写在body的底部(最快最有效)
- 引入外部js时,以defer的形式进行引入(第二快)
- 将js代码编写到document对象的DOMContentLoaded的回调函数中(第三快)
- 将js代码编写到window.onload的回调函数中(第四快)
DOM操作练习
1.点击切换图片
<body>
<div class="outer">
<p id="info">当前是第1张,一共7张图片</p>
<div class="img-warpper">
<img style="width: 720px; height: 400px;" src="./img/01.jpeg" alt="">
</div>
<div class="btn-warpper">
<button id="prev">上一张</button>
<button id="next">下一张</button>
</div>
</div>
<!-- js -->
<script>
// 点击按钮切换图片
// 获取info
const info = document.querySelector('#info');
// 获取图片
const imgs = document.querySelector('img');
// 获取按钮
const prev = document.querySelector('#prev');
const next = document.querySelector('#next');
// 方式1 (丧失灵活性)
// 绑定点击事件
// 上一张
let i = 1;
// info.textContent = `当前是第${i}张,一共7张图片`;
prev.onclick = function() {
i--;
imgs.src = `./img/0${i}.jpeg`
if(i <= 0) {
i = 7;
imgs.src = `./img/0${i}.jpeg`
}
info.textContent = `当前是第${i}张,一共7张图片`;
}
// 下一张
next.onclick = function() {
if(i<7) {
imgs.src = `./img/0${++i}.jpeg`;
}else if(i == 7) {
i = 1;
imgs.src = `./img/0${i}.jpeg`
}
info.textContent = `当前是第${i}张,一共7张图片`;
}
方式2
const arr = [
'./img/01.jpeg',
'./img/02.jpeg',
'./img/03.jpeg',
'./img/04.jpeg',
'./img/05.jpeg',
'./img/06.jpeg',
'./img/07.jpeg',
];
let a = 0;
// 上一张
prev.onclick = function() {
a--;
if(a < 0) {
a = arr.length - 1;
}
info.textContent = `当前是第${a + 1}张,一共${arr.length}张图片`;
imgs.src = arr[a];
}
// 下一张
next.onclick = function() {
a++;
if(a > arr.length -1) {
a = 0
}
info.textContent = `当前是第${a + 1}张,一共${arr.length}张图片`;
imgs.src = arr[a];
}
</script>
</body>
2.点击按钮选择喜好
<body>
<div>
<form action="#">
<div>
请选择你的爱好:
<input type="checkbox" id="check-all">全选
</div>
<div>
<input type="checkbox" name="hobby" value="动漫">动漫
<input type="checkbox" name="hobby" value="电影">电影
<input type="checkbox" name="hobby" value="游戏">游戏
<input type="checkbox" name="hobby" value="学习">学习
</div>
<div>
<button type="button" id="all">全选</button>
<button type="button" id="no">取消</button>
<button type="button" id="reverse">反选</button>
<button id="send">提交</button>
</div>
</form>
</div>
<script>
// 按钮全选功能
// 获取全选按钮
const btn = document.getElementById('all');
// 获取四个多选框
const hobbys = document.getElementsByName('hobby');
// 为全选按钮绑定单击事件
btn.onclick = function () {
//遍历多选框
for (let i = 0; i < hobbys.length; i++) {
hobbys[i].checked = true;
}
checkAll.checked = true;
}
// 取消全选按钮功能
// 获取取消按钮
const no = document.getElementById('no');
no.onclick = function () {
for (let i = 0; i < hobbys.length; i++) {
hobbys[i].checked = false;
}
checkAll.checked = false;
}
//反选按钮
// 获取反选按钮
const reverse = document.getElementById('reverse');
reverse.onclick = function () {
for (let i = 0; i < hobbys.length; i++) {
hobbys[i].checked = !hobbys[i].checked;
}
const checkBox = document.querySelectorAll('[name = hobby]:checked');
checkBox.length === hobbys.length ? checkAll.checked = true : checkAll.checked = false;
}
//提交按钮
// 获取提交按钮
const send = document.getElementById('send');
send.onclick = function () {
for (let i = 0; i < hobbys.length; i++) {
// hobbys[i].checked && alert(hobbys[i].value);
if (hobbys[i].checked) {
alert(hobbys[i].value);
}
}
}
// 大全选按钮
// 获取大全选按钮
const checkAll = document.getElementById('check-all');
checkAll.onclick = function () {
for (let i = 0; i < hobbys.length; i++) {
// if(checkAll.checked) {
// hobbys[i].checked = true;
// }else {
// hobbys[i].checked = false;
// }
// checkAll.checked ? hobbys[i].checked = true : hobbys[i].checked = false;
// hobbys[i].checked = checkAll.checked;
//在事件的响应函数中,this指向响应函数绑定的对象(箭头函数除外)
hobbys[i].checked = this.checked;
}
}
for (let i = 0; i < hobbys.length; i++) {
hobbys[i].onclick = function() {
const checkBox = document.querySelectorAll('[name = hobby]:checked');
// alert(checkBox.length);
checkBox.length === hobbys.length? checkAll.checked = true : checkAll.checked = false;
}
}
</script>
</body>
document.querySelectorAll('[name = hobby]:checked')
:
:checked
伪类选择器,只返回checked为true时的元素在事件的响应函数中,this指向响应函数绑定的对象(箭头函数除外)
元素的修改
<body>
<button id="btn1">添加</button>
<button id="btn2">替换</button>
<button id="btn3">删除</button>
<hr></hr>
<ul id="list">
<li id="zs">张三</li>
<li id="ls">李四</li>
<li id="rk">瑞克</li>
</ul>
<script>
const list = document.getElementById('list');
const btn1 = document.getElementById('btn1');
const btn2 = document.getElementById('btn2');
const btn3 = document.getElementById('btn3');
// 添加
btn1.onclick = function() {
// 添加节点
const li = document.createElement('li');
// 添加文本
li.textContent = '莫蒂';
// 添加属性
li.id = 'md';
console.log(li);
// 添加到DOM
// 为一个节点添加子节点
list.appendChild(li); //只能在结尾添加节点
list.insertAdjacentElement('beforeend', li); //可以在(子元素,或当前元素)开头,结尾添加节点
}
list.insertAdjacentHTML('afterbegin', '<li id="jk">杰克</li>');
//替换
btn2.onclick = function() {
const li = document.createElement('li');
li.textContent = '汤姆';
li.id = 'tm';
// 获取zs
const zs = document.getElementById('zs');
// 替换zs
zs.replaceWith(li);
}
// 删除
btn3.onclick = function() {
// 获取zs
const zs = document.getElementById('zs');
//id选择器不用获取元素对象也能进行操作
// 删除zs
zs.remove();
}
</script>
</body>
添加:
appendChild()
给一个节点添加子节点(只能在末尾添加子节点)insertAdjacentElement()
可以在(子元素,或当前元素)开头,结尾添加节点
beforeend
标签的最后afterbegin
标签的开始beforebegin
在当前元素的前边插入元素(兄弟元素)afterbegin
在当前元素的后边插入元素**(兄弟元素**)insertAdjacentHTML('<li id="id">xx</li>')
替换:
replaceWith()
使用一个元素替换一个元素删除:
remove()
删除一个元素
练习
<body>
<div class="outer">
<table>
<tbody>
<tr>
<th>姓名</th>
<th>邮件</th>
<th>薪资</th>
<th>操作</th>
</tr>
<tr>
<td>张三</td>
<td>zs@qq.com</td>
<td>13000</td>
<td><a href="#">删除</a></td>
</tr>
<tr>
<td>李四</td>
<td>ls@qq.com</td>
<td>10000</td>
<td><a href="#">删除</a></td>
</tr>
<tr>
<td>王五</td>
<td>ww@qq.com</td>
<td>15000</td>
<td><a href="#">删除</a></td>
</tr>
</tbody>
</table>
<form action="#">
<div>
<label for="name">姓名</label>
<input type="text" id="name">
</div>
<div>
<label for="email">邮件</label>
<input type="email" id="email">
</div>
<div style="margin-left: 46px">
<label for="salary">薪资</label>
<input type="number" id="number">
<button id="btn">添加</button>
</div>
</form>
</div>
<script>
//删除员工
// 获取删除超链接
const links = document.links;
// 绑定单击响应函数
function delEmp() {
// this指向绑定的响应函数绑定的对象
// console.log(this);
// 获取tr
const tr = this.parentNode.parentNode;
// 获取tr下的第一个td
const td = tr.getElementsByTagName('td')[0].textContent;
// 弹出提示框
let flag = confirm(`确认要删除[${td}]吗?`)
// 删除tr
flag? tr.remove() : '';
// 取消a标签超链接的默认行为
return false
}
for (let i=0; i<links.length; i++){
links[i].onclick = delEmp;
}
//添加员工
// 获取按钮
const btn = document.getElementById('btn');
// 获取tbody
const tbody = document.querySelector('tbody');
// 绑定单击响应函数
btn.onclick = function() {
// 获取文本框的值
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
const number = document.getElementById('number').value;
// 添加到 DOM(容易被xss攻击)
tbody.insertAdjacentHTML('beforeend',
`
<tr>
<td>${name}</td>
<td>${email}</td>
<td>${number}</td>
<td><a href="#">删除</a></td>
</tr>
`
);
const last = tbody.lastElementChild.lastElementChild.lastElementChild;
last.onclick = delEmp;
console.log(last)
// links[links.length - 1].onclick = delEmp;
return false;
}
</script>
</body>
取消标签的默认行为:
- 设置
javascript:;
表示引用一个空的js代码(只针对a标签的href属性)- 在单击响应函数里添加
return false
表示不执行标签的默认行为只适用于xx.xx = function(){})
节点的复制
<body>
<button id="btn">点我复制</button>
<ul id="list1">
<li id="l1">张三</li>
<li id="l2">李四</li>
<li id="l3">王五</li>
</ul>
<ul id="list2">
<li>杰克</li>
</ul>
<script>
const btn = document.getElementById('btn');
const list2 = document.getElementById('list2');
const l1 = document.getElementById("l1");
btn.onclick = function() {
// list2.appendChild(l1);
// 复制l1节点
const newL1 = l1.cloneNode(true);
newL1.id = 'newL1';
list2.appendChild(newL1);
}
</script>
</body>
复制节点:
元素.cloneNode()
:方法对节点进行复制时,他会复制节点的所有特点(包括各种属性),该方法默认只会复制当前节点,不会复制节点的节点,传递参数true作为参数时,会赋值文本节点.
元素的样式
<body>
<button id="btn">点击获取样式</button>
<div class="box1"></div>
<script>
const btn = document.getElementById('btn');
const box1 = document.getElementsByClassName('box1')[0];
btn.onclick = function() {
const styleObj = getComputedStyle(box1);
console.log(styleObj); //获取所有样式声明
console.log(styleObj.width);
//返回的width值是一个字符串因此在增加宽度时通过parsetInt取整后在计算
box1.style.width = parseInt(styleObj.width) + 100 + 'px';
// 获取box1的背景样式(注意写法改为驼峰)
console.log(styleObj.backgroundColor);
}
</script>
</body>
修改:
element.style.属性名 = '属性值'
:修改元素的内联样式,(注意:css样式的属性名如果带有-
则需要把属性名改为小驼峰)读取:
方法:
getComputedStyle()
😦该方法获取的样式值为字符串)
- 返回一个对象,该对象包括了当前元素所有的生效的样式
- 参数:1 获取样式的元素,2:要获取的伪元素
返回对象中的样式值,不一定都可以直接进行计算,因此在使用之前一定要确保值可以进行计算
属性:
- 获取元素内部的高度与宽度(包括内容区和内边距):
元素.clientHeight | clientWidth
- 获取元素可见框的高度与宽度(包括内容区和内边距和边框):
元素.offsetHeight | offsetWidth
- 获取元素滚动区域的高度和宽度:
元素.scrollHeight | scrollWidth
- 获取元素的定位父元素(如果所有父元素都没开启定位则为body):
元素.offsetParent
- 获取元素相对于定位父元素的偏移量:
元素.offsetTop | offsetLeft
- 获取或修改元素滚动条的偏移量:
元素.scrollTop| scrollLeft
操作class改变样式
<style>
.box1 {
background-color: aqua;
height: 100px;
}
.box2 {
width: 200px;
height: 200px;
background-color: #bfa;
margin: 10px;
border: 5px solid yellowgreen;
}
</style>
</head>
<body>
<button id="btn">点击改变样式</button>
<div class="box1"></div>
<script>
const btn = document.getElementById('btn');
const box1 = document.getElementsByClassName('box1')[0];
btn.onclick = function() {
// 通过style属性改变css样式会造成css与js代码的耦合(不完全分离,改变css样式要修改js代码)
// box1.style.width = '500px';
// 可以通过为box1添加class类的方法来改变css(不够灵活)
// box1.className += " box2";
// 通过classList来修改样式
// 添加
// box1.classList.add('box2');
// 移除
// box1.classList.remove('box2');
// 切换
// box1.classList.toggle('box2')
// 替换
box1.classList.replace('box1', "box2");
// 检查
console.log(box1.classList.contains('box2'));
}
</script>
</body>
元素.classList
:的属性的方法
- 是一个对象,对象提供了对当前元素的类的各种方法
元素.classList.add()
:为当前元素添加一个类元素.classList.remove()
:移除当前元素的一个类元素.classList.toggle()
:切换当前元素的类,有则移除没有则添加元素.classList.replace()
:替换当前元素的一个类,(不会对其他类产生影响)元素.classList.contains()
:检查当前元素是否存在一个类,返回一个布尔值
事件对象
<style>
.box1 {
background-color: aqua;
height: 200px;
width: 200px;
}
.box2 {
width: 170px;
height:170px;
background-color: #bfa;
}
.box3 {
width: 140px;
height: 140px;
background-color: rgb(13, 147, 192);
}
</style>
</head>
<body>
<div class="box1">
<div class="box2">
<div class="box3"></div>
</div>
</div>
<a id="baidu" href="https://www.baidu.com">点击跳转百度</a>
<script>
const box1 = document.getElementsByClassName('box1')[0];
const box2 = document.getElementsByClassName('box2')[0];
const box3 = document.getElementsByClassName('box3')[0];
const baidu = document.getElementById('baidu');
// 事件冒泡
box1.onclick = function(event) {
// 打印事件对象
console.log(event);
// 获取获取触发事件的对象(包含冒泡的触发)
console.log(event.target);
// 获取绑定事件的对象(通this)
console.log(event.currentTarget);
console.log(this);
alert('我是box1');
}
box2.addEventListener('click', function(event) {
alert('我是box2');
})
box3.onclick = (event) => {
//停止事件的传递
event.stopPropagation();
alert('我是box3');
}
baidu.addEventListener('click', (event) => {
alert('准备跳转');
// 取消默认行为
event.preventDefault();
})
</script>
</body>
事件对象:
- 事件对象是浏览器在事件触发时所创建的对象,该对象中封装了事件相关的各种信息
- 通过事件对象可以获取到事件的详细信息(列如鼠标的坐标,键盘的按键等)
- 浏览器在创建事件对象后,会将事件对象作为回调函数的参数传递,因此我们需要在回调函数中定义一个形参(一般为event)来接受事件
事件的冒泡(bubble):
- 事件的冒泡就是指事件的向上传递,当元素上的某个事件被出发后,其祖先元素上的相同事件也会被同时触发
- 冒泡的存在大大的简化了代码的编写
事件的冒泡(bubble)
<style>
.box1 {
background-color: aqua;
height: 50px;
width: 50px;
border-radius: 50%;
position: absolute;
}
.box2 {
width: 170px;
height:170px;
background-color: #bfa;
}
.box3 {
width: 140px;
height: 140px;
background-color: rgb(13, 147, 192);
}
.box4 {
width: 110px;
height: 110px;
background-color: rgb(168, 13, 192);
position: absolute;
bottom: 0;
}
</style>
</head>
<body>
<div class="box1"></div>
<div class="box2"></div>
<div class="box3">
<div class="box4"></div>
</div>
<script>
const box1 = document.getElementsByClassName('box1')[0];
const box2 = document.getElementsByClassName('box2')[0];
const box3 = document.getElementsByClassName('box3')[0];
const box4 = document.getElementsByClassName('box4')[0];
// 事件冒泡
document.onmousemove = function(event) {
box1.style.left = event.x + 'px';
box1.style.top = event.y + 'px';
}
box2.addEventListener('mousemove', function(event) {
//停止事件的传递
event.stopPropagation();
})
box3.onmousemove = (event) => {
alert('我是box3');
}
box4.onmousemove = (event) => {
alert('我是box4');
}
</script>
</body>
事件的冒泡与样式无关,与结构相关
事件的委派
<body>
<button id="btn">点击添加超链接</button>
<ul id="list">
<li><a href="javascript:;">超链接1</a></li>
<li><a href="javascript:;">超链接2</a></li>
<li><a href="javascript:;">超链接3</a></li>
</ul>
<script>
const btn = document.getElementById('btn');
const list = document.getElementById('list');
// 注意: 使用querySelector方法获取的元素节点对象返回的类数组不会实时刷新
// const links = list.querySelectorAll('a');
const links = list.getElementsByTagName('a');
btn.onclick = function(event) {
list.insertAdjacentHTML('beforeend', "<li><a href='javascript:;'>新超链接</a></li>")
}
// 冒泡
document.addEventListener('click', function(event) {
// alert(event.target.textContent);
// 判断事件是否由超链接触发
console.log([...links]);
if([...links].includes(event.target)) {
alert(event.target.textContent);
}
})
</script>
</body>
事件的委派通过冒泡,将本身的事件委派到器祖先元素实现,减少了代码的复杂度
事件的捕获
<body>
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
<script>
const box1 = document.getElementById('box1');
const box2 = document.getElementById('box2');
const box3 = document.getElementById('box3');
box1.addEventListener('click', (event) => {
alert('我是box1' + event.eventPhase);
}, true);
box2.addEventListener('click', (event) => {
alert('我是box2' + event.eventPhase);
});
box3.addEventListener('click', (event) => {
alert('我是box3' + event.eventPhase);
}, true);
</script>
</body>
事件的传播机制:
- 在DOM中,事件的传播可以分为三个阶段:
- 捕获阶段(有祖先元素向目标元素进行事件的捕获,默认情况下事件不会在捕获阶段触达)
- 目标阶段(触发事件)
- 冒泡阶段(由目标元素向祖先元素进行事件的传递)
- 事件的捕获,指事件有外向内传递(当前元素触发事件后,会从当前元素最大的祖先元素开始向当前元素进行事件捕获)
- 如果希望事件在捕获阶段开始触发事件,可以将
addEventListener
的第三个参数设置为true,一般情况下我们不希望在捕获阶段触发事件event.eventPhase
可以将事件的传播步骤用数字表示:
- 1代表捕获阶段
- 2代表目标阶段
- 3代表冒泡事件