目录
一、操作class
之前的修改样式的方法:元素.style.样式名 = 样式值存在一些问题:
1.如我们需要大量修改时,过于麻烦
2.会耦合,如我们在JS中对其样式进行修改,之后我们仍想要修改样式时,只修改样式表里的样式不行,还要对JS中之前修改的部分进行修改,会导致JS和CSS耦合
除了直接修改样式外,也可以通过修改class 属性来间接的修改样式
采用 元素.className += " class名",且class名前用空格,
因为一个元素可以设置多个class,多个class用空格隔开
通过class修改样式的好处:
1.可以一次性修改多个样式
2.对JS和CSS进行解耦, 即直接修改CSS样式表里的样式即可
元素.classList 是一个对象,对象中提供了对当前元素的类的各种操作方法
元素.classList.add( ) 向元素中添加一个或多个class
元素.classList.remove( ) 移除元素中的一个或多个class
元素.classList.toggle( ) 切换元素中的一个class(切换就是有就加上,没有就移除)
元素.classList.replace( ) 替换class,用后面的class替换前面的class
元素.classList.contains( ) 检查一个元素中是否含有某个class,有就返回true,没有就false
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>document</title>
<style>
.box1{
width:200px;
height: 200px;
background-color: #bfa;
}
.box2{
background-color: yellow;
width: 300px;
height: 500px;
border: 10px red solid;
}
</style>
</head>
<body>
<button id="btn">点我一下</button>
<hr>
<div class="box1"></div>
<script>
/*
点击按钮后,修改box1的宽度
*/
const btn = document.getElementById("btn")
const box1 = document.querySelector(".box1")
btn.onclick = function(){
// 除了直接修改样式外,也可以通过修改class 属性来间接的修改样式
// box1.className = "box2" //这样写代表直接用box2来取代box1的class,直接替换了
// box1.className += " box2"//我们想进行的是在box1的基础上,再传入类box2的样式,
//所以采用+= " box2",且box2前用空格,
// 因为一个元素可以设置多个class,多个class用空格隔开
// 元素.classList
// box1.classList.add("box2")//向元素中添加class,box2
// box1.classList.add("box2","box3","box4")//向元素中添加多个class
// box1.classList.add("box1")//由于元素中已有box1 的class,所以不会添加,
// // 而对于 box1.className += " box1"则会添加进去,因为其相当于进行拼串
// box1.classList.remove("box1","box3")
// box1.classList.toggle("box2")
// box1.classList.replace("box1","box2")//用box2替换box1
let result = box1.classList.contains("box3")
console.log(result);
}
</script>
</body>
二、事件对象简介
事件对象
- 事件对象是由浏览器在事件触发时所创建的对象,
这个对象中封装了事件相关的各种信息
- 通过事件对象可以获取到事件的详细信息
比如:鼠标的坐标、键盘的按键……
- 浏览器在创建事件对象后,会将事件对象作为响应函数的参数传递,
所以我们可以在事件的回调函数中定义一个形参来接收事件对象
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>document</title>
<style>
#box1{
width: 300px;
height: 300px;
border: 10px greenyellow solid;
}
</style>
</head>
<body>
<div id="box1"></div>
<script>
const box1 = document.getElementById("box1")
//在回调函数中定义一个形参来接收事件对象
box1.onmousemove = function(event){
console.log(event);
box1.textContent = event.clientX + ',' + event.clientY
// 将鼠标移动事件发生时的鼠标的坐标传入box1内容中
}
</script>
</body>
</html>
三、Event对象
在DOM中存在多种不同类型的事件对象,如PointerEvent、MouseEvent
- 多种事件对象有一个共同的祖先 Event
- event.target 表示的是触发事件的对象
- event.currentTarget( ) 绑定事件的对象(同this)
箭头函数中无this(this是其外层作用域),可以使用currentTarget获得箭头函数的this
- event.stopPropagation( ) 停止事件的传导
- event.currentTarget( ) 停止事件的传导
- event.preventDefault( ) 取消默认行为,比return false更好
- 事件的冒泡(bubble)
- 事件的冒泡就是指事件的向上传导
- 当元素上的某个事件被触发后,其祖先元素上的相同事件也会同时被触发
- 冒泡的存在大大的简化了代码的编写,但是在一些场景下我们并不希望冒泡存在
不希望事件冒泡时,我们可以通过事件对象来取消冒泡
使用event.stopPropagation( )停止事件的传导,可以取消事件冒泡
在事件的响应函数中:
Event.target 表示的是触发事件的对象,由于事件的冒泡存在,触发事件的对象不一定是绑定事件的对象(建议使用target属性,而不建议使用this)
this 绑定事件的对象
<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>
#box1{
width: 300px;
height: 300px;
background-color: greenyellow;
}
#box2{
width: 250px;
height: 250px;
background-color: #ff0;
}
#box3{
width: 200px;
height: 200px;
background-color: orange;
}
</style>
</head>
<body>
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
<a id="ma" href="https://www.baidu.com">超链接</a>
<script>
const box1 = document.getElementById("box1")
const box2 = document.getElementById("box2")
const box3 = document.getElementById("box3")
const ma = document.getElementById("ma")
box1.addEventListener("click",function (event) {
console.log(event.target);//表示的是触发事件的对象,
// 当我们点击box2时,打印<div id="box2">...</div>
// 当我们点击box1时,打印<div id="box1">...</div>
console.log(this);//<div id="box1">...</div>,绑定事件的对象
console.log(event.currentTarget);
alert("Hello,我是box1")
})
box2.addEventListener("click",function(event){
alert("我是box2")//会产生事件的冒泡,当元素上的某个事件被触发后,其祖先元素上的相同事件也会同时被触发
// 当点击box2时,而box1是box2的父元素,所以也会触发点击box1,换句话说,点击box2就相当于把box1也点了
})
box3.addEventListener("click",function(event){
event.stopPropagation()//取消事件的传导,这样此时我们点击box3时,只会触发box3,而不会触发box2,box1
alert("我是box3")
})
ma.onclick = function(event){
alert("被点了~~")
// return false //通过return false取消超链接的默认行文,
// 但该方法只能对 xxx.xxx = function(){}形式有效 ,如对于xxx.addEventListener()无效
event.preventDefault()//取消默认行为
}
</script>
</body>
四、事件的冒泡
事件的冒泡和元素的样式无关,只和结构相关
大部分情况下,事件的冒泡是有益的
<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>
#box1{
width: 100px;
height: 100px;
background-color: greenyellow;
border-radius: 50%;
position: absolute;/* 开启绝对定位 */
}
#box2{
width: 500px;
height: 500px;
background-color: orange;
}
#box3{
width: 200px;
height: 200px;
background-color: tomato;
}
#box4{
width: 100px;
height: 100px;
background-color: skyblue;
position: absolute;
bottom: 0;
/* 此时虽然box4和box3不在一起,但点击box4时仍会触发box3,
因为事件的冒泡和元素的样式无关,只和结构相关 */
}
</style>
</head>
<body>
<div id="box1"></div>
<div id="box2"></div>
<div id="box3" onclick="alert(3)">
<div id="box4" onclick="alert(4)"></div>
</div>
<script>
/*
使小绿球可以跟随鼠标一起移动
*/
const box1 = document.getElementById("box1")
const box2 = document.getElementById("box2")
// box1.addEventListener("mousemove",(event)=>{
// box1.style.left = event.x + "px" //event.x与event.clientX相同,注意获得的值没有单位,要加单位
// box1.style.top = event.y + "px"
// /*
// 这种写法获得的结果,小绿球只能跟着鼠标向右下移动
// 原因是把事件绑定给box1,意味着只有鼠标在box1上时才会触发mousemove事件,事件绑错人了
// */
// })
document.addEventListener("mousemove",(event)=>{
box1.style.left = event.x + "px" //event.x与event.clientX相同,注意获得的值没有单位,要加单位
box1.style.top = event.y + "px"
/*
虽然设置了box2,但鼠标在box2中时仍可以移动小绿球
原因是因为冒泡的存在,在box2触发移动,冒泡给父元素body,再冒泡给html,再冒给document,
所以由于事件的冒泡存在,即使在box2中,也会触发document的事件
*/
})
// box2.addEventListener("mousemove",(event)=>{
// event.stopPropagation()
// })
/* 设置了取消事件的冒泡,当鼠标在box2时,不能移动小绿球 */
</script>
</body>
五、事件的委派
将伪数组转换为数组的方法:
1.Array.from(伪数组)
2.[...伪数组] 使用展开运算符
事件的委派:委派就是将本该绑定给多个元素的事件,统一绑定给document(或者这些元素的祖先元素,但一般都是给document),这样可以降低代码复杂度方便维护。
<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>
#box1{
width: 100px;
height: 100px;
background-color: greenyellow;
border-radius: 50%;
position: absolute;/* 开启绝对定位 */
}
#box2{
width: 500px;
height: 500px;
background-color: orange;
}
#box3{
width: 200px;
height: 200px;
background-color: tomato;
}
#box4{
width: 100px;
height: 100px;
background-color: skyblue;
position: absolute;
bottom: 0;
/* 此时虽然box4和box3不在一起,但点击box4时仍会触发box3,
因为事件的冒泡和元素的样式无关,只和结构相关 */
}
</style>
</head>
<body>
<button id="btn">点我一下</button>
<hr>
<ul id="list">
<li><a href="javascript:;">链接一</a></li>
<li><a href="javascript:;">链接二</a></li>
<li><a href="javascript:;">链接三</a></li>
<li><a href="javascript:;">链接四</a></li>
</ul>
<script>
/*
我有一个希望:
只绑定一次事件,即可以让所有的超链接(包括当前的和未来新建的超链接)都具有这些事件
思路:
可以将事件统一绑定给document,这样点击超链接时由于事件的冒泡,
会导致document上的点击事件被触发,这样只绑定一次,所有的超链接都会具有这些事件
但这样给document绑定事件后,对于document里所有的内容在点击是都会产生事件
在执行代码前,先来判断一下事件是由谁触发,此时我们希望事件由超链接触发
*/
/*
点击链接时显示链接中的文字
*/
const list = document.getElementById("list")
const btn = document.getElementById("btn")
// 获取list中所有的超链接
const links = list.getElementsByTagName("a")
// for(let i=0;i<links.length;i++){
// links[i].addEventListener("click",event =>{
// alert(event.target.textContent)
// })
// }
// /*
// 点击按钮后,在ul中添加一个新的li
// */
btn.addEventListener("click",()=>{
list.insertAdjacentHTML("beforeend","<li><a href='javascript:;'>新超链接</a></li>")
})
// 但对于这些新建的超链接点击时不会显示链接中的内容
// document.addEventListener("click",(event)=>{
// alert(event.target.textContent)
// })
// 但这样给document绑定事件后,对于document里所有的内容在点击是都会产生事件
document.addEventListener("click",(event)=>{
// 在执行代码前,先来判断一下事件是由谁触发,此时我们希望事件由超链接触发
// 检查event.target 是否在 links中存在,links是一个伪数组
// 将Links伪数组转换为数组Array.from(links) 或者[...links]
if([...links].includes(event.target)){
alert(event.target.textContent)
}
})
</script>
</body>
六、事件的捕获
事件的传播机制:
- 在DOM中,事件的传播可以分为三个阶段:
1. 事件的捕获阶段(由祖先元素向目标元素进行事件的捕获,到目标元素就停止捕获)
默认情况下,事件不会在捕获阶段触发,因此事件的触发从里往外(冒泡)
2. 目标阶段(目标就是触发事件的对象)
3. 冒泡阶段(由目标元素向祖先元素进行事件的冒泡)
- 事件的捕获,指事件从外向内的传导,
当我们当前元素触发事件以后,会先从当前元素最大的祖先元素开始向当前元素开始进行事件的捕获
- 如果希望在捕获阶段触发事件,可以在addEventListener的第三个参数设置为true
一般情况下我们不希望事件在捕获阶段触发,所以通常都不需要设置第三个参数
event.eventPhase
表示事件触发的阶段(是在捕获阶段,还是目标阶段或者冒泡阶段触发的)
- 返回的是数字:
0 表示没有触发事件
1 表示捕获阶段
2 表示目标阶段
3 表示冒泡阶段
<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>
#box1{
width: 300px;
height: 300px;
background-color: greenyellow;
}
#box2{
width: 200px;
height: 200px;
background-color:orange ;
}
#box3{
width: 100px;
height: 100px;
background-color: tomato;
}
</style>
</head>
<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")
// 如果希望在捕获阶段触发事件,可以在addEventListener的第三个参数设置为true
box1.addEventListener("click",event=>{
alert("1" + event.eventPhase) //表示事件的触发阶段
// event.stopPropagation()//
// alert(1)
},true)
box2.addEventListener("click",event=>{
alert("2" + event.eventPhase)
// alert(2)
},true)
box3.addEventListener("click",event=>{
alert("3" + event.eventPhase)
// alert(3)
},true)
// 事件的捕获,当我们点击box3时,先从document找,然后html、body、box1、box2、box3
</script>
</body>