随机点名案例
业务分析:
- 点击开始按钮随机抽取数组中的一个数据,放到页面中
- 点击结束按钮删除数组当前抽取的一个数据
- 当抽取到最后一个数据的时候,两个按钮同时禁用(只剩最后一个数据不用抽了)
核心:利用定时器快速展示,停止定时器结束展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
h2 {
text-align: center;
}
.box {
width: 600px;
margin: 50px auto;
display: flex;
font-size: 25px;
line-height: 40px;
}
.qs {
width: 450px;
height: 40px;
color: red;
}
.btns {
text-align: center;
}
.btns button {
width: 120px;
height: 35px;
margin: 0 50px;
}
</style>
</head>
<body>
<h2>随机点名</h2>
<div class="box">
<span>名字是:</span>
<div class="qs">这里显示姓名</div>
</div>
<div class="btns">
<button class="start">开始</button>
<button class="end">结束</button>
</div>
<script>
// 数据数组
const arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
const qs=document.querySelector('.qs')
// 业务1. 开始按钮模块
// 1.1 获取开始按钮对象\
let timerId=0
let random=0
const start =document.querySelector('.start')
//1.2添加点击事件
start.addEventListener('click',function(){
timerId =setInterval(function(){
//随机数
random=parseInt(Math.random()*arr.length)
// console.log(arr[random])
qs.innerHTML=arr[random]
},35)
//如果数组中只剩一个值,就不需要抽取了,让两个按钮禁用即可
if(arr.length===1){
start.disabled=true
end.disabled=true
}
})
// 2.关闭按钮模块
const end=document.querySelector('.end')
end.addEventListener('click',function(){
//关闭定时器
clearInterval(timerId)
//结束之后 可以删除掉当前抽取的那个数组元素
arr.splice(random,1)
console.log(arr)
})
</script>
</body>
</html>
事件监听版本
- DOML0
事件源.on事件=function(){}
const btn=document.querySelector('button')
btn.onclick=function(){
alert(11)
}
- DOML2
事件源.addEventListener(事件,事件处理函数)
- 区别:
on方式会被覆盖,addEventListener方式可绑定多次,拥有事件更多特性,推荐使用
事件类型
鼠标事件
鼠标触发
- click 鼠标点击
- mouseenter 鼠标经过
- mouseleave 鼠标离开
焦点事件
表单获得光标
- focus 获得焦点
- blur 失去焦点
const input=document.querySelector('input')
input.addEventListener('focus',function(){
console.log('有焦点触发')
})
input.addEventListener('blur',function(){
console.log('失去焦点触发')
})
键盘事件
键盘触发
- Keydown 键盘按下触发
- Keyup 键盘抬起触发
// 1. 键盘事件
const input=document.querySelector('input')
input.addEventListener('keydown',function(){
console.log('键盘按下了')
})
input.addEventListener('keyup',function(){
console.log('键盘弹起了')
})
// 2.用户输入文本事件 input
input.addEventListener('input',function(){
console.log(input.value)//获取输入内容
})
文本事件
表单输入触发
input 用户输入事件
轮播图点击切换
需求:当点击左右的按钮,可以切换轮播图
分析:
- 右侧按钮点击,变量++,如果大于等于8,则复原0
- 左侧按钮点击,变量--,如果小于0,则复原最后一张
- 鼠标经过暂停计时器
- 鼠标离开开启定时器
<!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>轮播图点击切换</title>
<style>
* {
box-sizing: border-box;
}
.slider {
width: 560px;
height: 400px;
overflow: hidden;
}
.slider-wrapper {
width: 100%;
height: 320px;
}
.slider-wrapper img {
width: 100%;
height: 100%;
display: block;
}
.slider-footer {
height: 80px;
background-color: rgb(100, 67, 68);
padding: 12px 12px 0 12px;
position: relative;
}
.slider-footer .toggle {
position: absolute;
right: 0;
top: 12px;
display: flex;
}
.slider-footer .toggle button {
margin-right: 12px;
width: 28px;
height: 28px;
appearance: none;
border: none;
background: rgba(255, 255, 255, 0.1);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.slider-footer .toggle button:hover {
background: rgba(255, 255, 255, 0.2);
}
.slider-footer p {
margin: 0;
color: #fff;
font-size: 18px;
margin-bottom: 10px;
}
.slider-indicator {
margin: 0;
padding: 0;
list-style: none;
display: flex;
align-items: center;
}
.slider-indicator li {
width: 8px;
height: 8px;
margin: 4px;
border-radius: 50%;
background: #fff;
opacity: 0.4;
cursor: pointer;
}
.slider-indicator li.active {
width: 12px;
height: 12px;
opacity: 1;
}
</style>
</head>
<body>
<div class="slider">
<div class="slider-wrapper">
<img src="./images/slider01.jpg" alt="" />
</div>
<div class="slider-footer">
<p>对人类来说会不会太超前了?</p>
<ul class="slider-indicator">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<div class="toggle">
<button class="prev"><</button>
<button class="next">></button>
</div>
</div>
</div>
<script>
// 1. 初始数据
const Data = [
{ url: './images/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
{ url: './images/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
{ url: './images/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
{ url: './images/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
{ url: './images/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
{ url: './images/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
{ url: './images/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
{ url: './images/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
]
//获取元素
const img=document.querySelector('.slider-wrapper img')
const p=document.querySelector('.slider-footer p')
const footer=document.querySelector('.slider-footer')
// 1.右按钮业务
// 1.1 获取右侧按钮
const next=document.querySelector('.next')
let i=0
// 1.2 注册点击事件
next.addEventListener('click',function(){
// console.log(11)
i++
// 1.6 判断条件 如果大于8 就复原为0
i=i>=Data.length?0:i
// 1.3得到对应的对象
// console.log(Data[i])
img.src=Data[i].url
p.innerHTML=Data[i].title
footer.style.backgroundColor=Data[i].color
// 1.5 更换小圆点 先移除原来的类名 当前li再添加 这个类名
document.querySelector('.slider-indicator .active').classList.remove('active')
document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
})
// 1.右按钮业务
// 1.1 获取左侧按钮
const prev=document.querySelector('.prev')
prev.addEventListener('click',function(){
// console.log(11)
i--
// 1.6 判断条件 如果小于0 则跑到最后一张图片索引号是7
i=i<0?Data.length-1:i
// 1.3得到对应的对象
// console.log(Data[i])
img.src=Data[i].url
p.innerHTML=Data[i].title
footer.style.backgroundColor=Data[i].color
// 1.5 更换小圆点 先移除原来的类名 当前li再添加 这个类名
document.querySelector('.slider-indicator .active').classList.remove('active')
document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
})
//3.自动播放模块
let timerId=setInterval(function(){
//利用js自动调用点击事件 click必须加()
next.click()
},1000)
// 4.鼠标经过大盒子,停止定时器
const slider=document.querySelector('.slider')
//注册事件
slider.addEventListener('mouseenter',function(){
//停止定时器
clearInterval(timerId)
})
// 5.鼠标离开大盒子,开启定时器
slider.addEventListener('mouseleave',function(){
//开启定时器
timerId=setInterval(function(){
//利用js自动调用点击事件 click必须加()
next.click()
},1000)
})
</script>
</body>
</html>
可以将左右按钮的公共样式写到一个函数中,需要时直接调用即可
<!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>轮播图点击切换</title>
<style>
* {
box-sizing: border-box;
}
.slider {
width: 560px;
height: 400px;
overflow: hidden;
}
.slider-wrapper {
width: 100%;
height: 320px;
}
.slider-wrapper img {
width: 100%;
height: 100%;
display: block;
}
.slider-footer {
height: 80px;
background-color: rgb(100, 67, 68);
padding: 12px 12px 0 12px;
position: relative;
}
.slider-footer .toggle {
position: absolute;
right: 0;
top: 12px;
display: flex;
}
.slider-footer .toggle button {
margin-right: 12px;
width: 28px;
height: 28px;
appearance: none;
border: none;
background: rgba(255, 255, 255, 0.1);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.slider-footer .toggle button:hover {
background: rgba(255, 255, 255, 0.2);
}
.slider-footer p {
margin: 0;
color: #fff;
font-size: 18px;
margin-bottom: 10px;
}
.slider-indicator {
margin: 0;
padding: 0;
list-style: none;
display: flex;
align-items: center;
}
.slider-indicator li {
width: 8px;
height: 8px;
margin: 4px;
border-radius: 50%;
background: #fff;
opacity: 0.4;
cursor: pointer;
}
.slider-indicator li.active {
width: 12px;
height: 12px;
opacity: 1;
}
</style>
</head>
<body>
<div class="slider">
<div class="slider-wrapper">
<img src="./images/slider01.jpg" alt="" />
</div>
<div class="slider-footer">
<p>对人类来说会不会太超前了?</p>
<ul class="slider-indicator">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<div class="toggle">
<button class="prev"><</button>
<button class="next">></button>
</div>
</div>
</div>
<script>
// 1. 初始数据
const Data = [
{ url: './images/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
{ url: './images/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
{ url: './images/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
{ url: './images/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
{ url: './images/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
{ url: './images/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
{ url: './images/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
{ url: './images/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
]
//获取元素
const img=document.querySelector('.slider-wrapper img')
const p=document.querySelector('.slider-footer p')
const footer=document.querySelector('.slider-footer')
// 1.右按钮业务
// 1.1 获取右侧按钮
const next=document.querySelector('.next')
let i=0
// 1.2 注册点击事件
next.addEventListener('click',function(){
// console.log(11)
i++
// 1.6 判断条件 如果大于8 就复原为0
i=i>=Data.length?0:i
toggle()
})
// 1.右按钮业务
// 1.1 获取左侧按钮
const prev=document.querySelector('.prev')
prev.addEventListener('click',function(){
// console.log(11)
i--
// 1.6 判断条件 如果小于0 则跑到最后一张图片索引号是7
i=i<0?Data.length-1:i
toggle()
})
//声明一个渲染函数作为复用
function toggle(){
// 1.3得到对应的对象
// console.log(Data[i])
img.src=Data[i].url
p.innerHTML=Data[i].title
footer.style.backgroundColor=Data[i].color
// 1.5 更换小圆点 先移除原来的类名 当前li再添加 这个类名
document.querySelector('.slider-indicator .active').classList.remove('active')
document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
}
//3.自动播放模块
let timerId=setInterval(function(){
//利用js自动调用点击事件 click必须加()
next.click()
},1000)
// 4.鼠标经过大盒子,停止定时器
const slider=document.querySelector('.slider')
//注册事件
slider.addEventListener('mouseenter',function(){
//停止定时器
clearInterval(timerId)
})
// 5.鼠标离开大盒子,开启定时器
slider.addEventListener('mouseleave',function(){
//开启定时器
timerId=setInterval(function(){
//利用js自动调用点击事件 click必须加()
next.click()
},1000)
})
</script>
</body>
</html>
小米搜索框案例
<!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;
box-sizing: border-box;
}
ul {
list-style: none;
}
.mi {
position: relative;
width: 223px;
margin: 100px auto;
}
.mi input {
width: 223px;
height: 48px;
padding: 0 10px;
font-size: 14px;
line-height: 48px;
border: 1px solid #e0e0e0;
outline: none;
}
.mi .search {
border: 1px solid #ff6700;
}
.result-list {
display: none;
position: absolute;
left: 0;
top: 48px;
width: 223px;
border: 1px solid #ff6700;
border-top: 0;
background: #fff;
}
.result-list a {
padding: 6px 15px;
font-size: 12px;
color: #424242;
text-decoration: none;
}
.result-list a:hover {
background-color: #eee;
}
</style>
</head>
<body>
<div class="mi">
<input type="search" placeholder="小米笔记本">
<ul class="result-list">
<li><a href="#">全部商品</a></li>
<li><a href="#">小米11</a></li>
<li><a href="#">小米10S</a></li>
<li><a href="#">小米笔记本</a></li>
<li><a href="#">小米手机</a></li>
<li><a href="#">黑鲨4</a></li>
<li><a href="#">空调</a></li>
</ul>
</div>
<script>
const input=document.querySelector('[type=search]')
const ul=document.querySelector('.result-list')
console.log(input)
// 2.监听事件 获得焦点
input.addEventListener('focus',function(){
ul.style.display='block'
input.classList.add('search')
})
//3.监听事件 失去焦点
input.addEventListener('blur',function(){
ul.style.display='none'
input.classList.remove('search')
})
</script>
</body>
</html>
评论字数统计
需求:用户输入文字,可以计算用户输入的字数
分析:
- 判断用输入事件 input
- 不断取得文本框里的字符长度,文本域.value.length
- 把获得数字给下面文本框
<!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>评论回车发布</title>
<style>
.wrapper {
min-width: 400px;
max-width: 800px;
display: flex;
justify-content: flex-end;
}
.avatar {
width: 48px;
height: 48px;
border-radius: 50%;
overflow: hidden;
background: url(./images/avatar.jpg) no-repeat center / cover;
margin-right: 20px;
}
.wrapper textarea {
outline: none;
border-color: transparent;
resize: none;
background: #f5f5f5;
border-radius: 4px;
flex: 1;
padding: 10px;
transition: all 0.5s;
height: 30px;
}
.wrapper textarea:focus {
border-color: #e4e4e4;
background: #fff;
height: 50px;
}
.wrapper button {
background: #00aeec;
color: #fff;
border: none;
border-radius: 4px;
margin-left: 10px;
width: 70px;
cursor: pointer;
}
.wrapper .total {
margin-right: 80px;
color: #999;
margin-top: 5px;
opacity: 0;
transition: all 0.5s;
}
.list {
min-width: 400px;
max-width: 800px;
display: flex;
}
.list .item {
width: 100%;
display: flex;
}
.list .item .info {
flex: 1;
border-bottom: 1px dashed #e4e4e4;
padding-bottom: 10px;
}
.list .item p {
margin: 0;
}
.list .item .name {
color: #FB7299;
font-size: 14px;
font-weight: bold;
}
.list .item .text {
color: #333;
padding: 10px 0;
}
.list .item .time {
color: #999;
font-size: 12px;
}
</style>
</head>
<body>
<div class="wrapper">
<i class="avatar"></i>
<textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea>
<button>发布</button>
</div>
<div class="wrapper">
<span class="total">0/200字</span>
</div>
<div class="list">
<div class="item" style="display: none;">
<i class="avatar"></i>
<div class="info">
<p class="name">清风徐来</p>
<p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p>
<p class="time">2022-10-10 20:29:21</p>
</div>
</div>
</div>
<script>
const tx=document.querySelector('#tx')
const total=document.querySelector('.total')
// 1. 当文本域获得了焦点,就让total显示出来
tx.addEventListener('focus',function(){
total.style.opacity=1
})
//2. 当文本域失去了焦点,就让total隐藏
tx.addEventListener('blur',function(){
total.style.opacity=0
})
//3.检测用户输入
tx.addEventListener('input',function(){
//console.log(tx.value.length) 得到输入的长度
total.innerHTML=`${tx.value.length}/200字`
})
</script>
</body>
</html>
事件对象
获取事件对象
- 事件对象是什么
也是个对象,这个对象里有事件触发时的相关信息
例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息
- 使用场景
可以判断用户按下哪个键,比如按下回车键可以发布新闻
可以判断鼠标点击了哪个元素,从而做出相应的操作
- 语法:
在事件绑定的回调函数的第一个参数就是事件对象
一般命名为event,ev,e
元素.addEventListener('click',function(e)){}
事件对象常用属性
- type:获取当前的事件类型
- clientX/clientY:获取光标对于浏览器可见窗口左上角的位置
- offsetX/offsetY:获取光标相对于DOM元素左上角的位置
- key:用户按下的键盘键的值,不提倡使用keyCode
trim方法
作用:去除字符串两边的空格,中间的空格保留
const str=' pink'
console.log(str.trim())
评论回车发布
需求:按下回车键,可以发布信息
- 用到按下键盘事件keydown或者keyup都可以
- 如果用户按下的是回车键盘,则发布信息
- 让留言信息模块显示把拿到的数据渲染到对应标签内部
小tip:用户按下回车之后,input文本框里的文字会清除,且若用户输出的全为空格,则不输出,输出结果去除用户内容左右两端的空格
<!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>评论回车发布</title>
<style>
.wrapper {
min-width: 400px;
max-width: 800px;
display: flex;
justify-content: flex-end;
}
.avatar {
width: 48px;
height: 48px;
border-radius: 50%;
overflow: hidden;
background: url(./images/bg01.jpg) no-repeat center / cover;
margin-right: 20px;
}
.wrapper textarea {
outline: none;
border-color: transparent;
resize: none;
background: #f5f5f5;
border-radius: 4px;
flex: 1;
padding: 10px;
transition: all 0.5s;
height: 30px;
}
.wrapper textarea:focus {
border-color: #e4e4e4;
background: #fff;
height: 50px;
}
.wrapper button {
background: #00aeec;
color: #fff;
border: none;
border-radius: 4px;
margin-left: 10px;
width: 70px;
cursor: pointer;
}
.wrapper .total {
margin-right: 80px;
color: #999;
margin-top: 5px;
opacity: 0;
transition: all 0.5s;
}
.list {
min-width: 400px;
max-width: 800px;
display: flex;
}
.list .item {
width: 100%;
display: flex;
}
.list .item .info {
flex: 1;
border-bottom: 1px dashed #e4e4e4;
padding-bottom: 10px;
}
.list .item p {
margin: 0;
}
.list .item .name {
color: #FB7299;
font-size: 14px;
font-weight: bold;
}
.list .item .text {
color: #333;
padding: 10px 0;
}
.list .item .time {
color: #999;
font-size: 12px;
}
</style>
</head>
<body>
<div class="wrapper">
<i class="avatar"></i>
<textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea>
<button>发布</button>
</div>
<div class="wrapper">
<span class="total">0/200字</span>
</div>
<div class="list">
<div class="item" style="display: none;">
<i class="avatar"></i>
<div class="info">
<p class="name">清风徐来</p>
<p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p>
<p class="time">2022-10-10 20:29:21</p>
</div>
</div>
</div>
<script>
const tx=document.querySelector('#tx')
const total=document.querySelector('.total')
const item=document.querySelector('.item')
const text=document.querySelector('.text')
// 1. 当文本域获得了焦点,就让total显示出来
tx.addEventListener('focus',function(){
total.style.opacity=1
})
//2. 当文本域失去了焦点,就让total隐藏
tx.addEventListener('blur',function(){
total.style.opacity=0
})
//3.检测用户输入
tx.addEventListener('input',function(){
//console.log(tx.value.length) 得到输入的长度
total.innerHTML=`${tx.value.length}/200字`
})
// 4.按下回车键发布评论
tx.addEventListener('keyup',function(e){
//只有按下的是回车键,才会触发
if(e.key==='Enter'){
// console.log(11) 测试
if(tx.value.trim()!==''){//输出内容不全为空格
item.style.display='block'
// console.log(tx.value)
text.innerHTML=tx.value
}
//等我们按下回车,结束,清空input里的值
tx.value=''
//按下回车之后,就要把字符统计复原
total.innerHTML='0/200字'
}
})
</script>
</body>
</html>
环境对象
环境对象指的是函数内部特殊的变量this,它代表着当前函数运行时所处的环境
作用:弄清楚this的指向,可以让我们的代码更简洁
- 函数的调用方式不同,this指向的对象也不同
- 谁调用,this就是谁(粗略规则)
- 直接调用函数,其实就是相当于是window,函数,所以this指代window
//每个函数里面都有this 环境对象 普通函数里面this指向的是window
// function fn(){
// console.log(this)
// }
// window.fn()
const btn=document.querySelector('button')
btn.addEventListener('click',function(){
// console.log(this)//this指向函数的调用者 在这里即btn
//btn.style.color='red'
this.style.color='red'
})
回调函数
如果将函数A作为参数传递给函数B时,就称函数A为回调函数
简单理解,当一个函数作为参数传递给另外一个函数的时候,这个函数就是回调函数
Tab栏切换
<!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>tab栏切换</title>
<style>
* {
margin: 0;
padding: 0;
}
.tab {
width: 590px;
height: 340px;
margin: 20px;
border: 1px solid #e4e4e4;
}
.tab-nav {
width: 100%;
height: 60px;
line-height: 60px;
display: flex;
justify-content: space-between;
}
.tab-nav h3 {
font-size: 24px;
font-weight: normal;
margin-left: 20px;
}
.tab-nav ul {
list-style: none;
display: flex;
justify-content: flex-end;
}
.tab-nav ul li {
margin: 0 20px;
font-size: 14px;
}
.tab-nav ul li a {
text-decoration: none;
border-bottom: 2px solid transparent;
color: #333;
}
.tab-nav ul li a.active {
border-color: #e1251b;
color: #e1251b;
}
.tab-content {
padding: 0 16px;
}
.tab-content .item {
display: none;
}
.tab-content .item.active {
display: block;
}
</style>
</head>
<body>
<div class="tab">
<div class="tab-nav">
<h3>每日特价</h3>
<ul>
<li><a class="active" href="javascript:;">精选</a></li>
<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>
</div>
<div class="tab-content">
<div class="item active"><img src="./images1/tab00.png" alt="" /></div>
<div class="item"><img src="./images1/tab01.png" alt="" /></div>
<div class="item"><img src="./images1/tab02.png" alt="" /></div>
<div class="item"><img src="./images1/tab03.png" alt="" /></div>
<div class="item"><img src="./images1/tab04.png" alt="" /></div>
</div>
</div>
<script>
// 1.a 模块制作 要给5个链接绑定鼠标经过事件
// 1.1获取a元素
const as=document.querySelectorAll('.tab-nav a')
console.log(as)
for(let i=0;i<as.length;i++){
// console.log(as[i])
as[i].addEventListener('mouseenter',function(){
// console.log('鼠标经过')
//排他思想
// 先去除类名active
document.querySelector('.tab-nav .active').classList.remove('active')
// 添加类名active
this.classList.add('active')
//下面5个大盒子一一对应 .item
document.querySelector('.tab-content .active').classList.remove('active')
// 对应序号的那个item显示添加 active类
document.querySelector(`.tab-content .item:nth-child(${i+1})`).classList.add('active')
})
}
</script>
</body>
</html>
全选文本框案例1
需求:用户点击全选,则下面复选框全部选择,取消全选则全部取消
分析:
- 全选复选框点击,可以得到当前按钮的checked
- 把下面所有的小复选框状态checked,改为和全选复选框一致
小tip:
.类名:checked{},可直接设置多选框被选中之后的样式·
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #c0c0c0;
width: 500px;
margin: 100px auto;
text-align: center;
}
th {
background-color: #09c;
font: bold 16px "微软雅黑";
color: #fff;
height: 24px;
}
td {
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}
.allCheck {
width: 80px;
}
</style>
</head>
<body>
<table>
<tr>
<th class="allCheck">
<input type="checkbox" name="" id="checkAll"> <span class="all">全选</span>
</th>
<th>商品</th>
<th>商家</th>
<th>价格</th>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck">
</td>
<td>小米手机</td>
<td>小米</td>
<td>¥1999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck">
</td>
<td>小米净水器</td>
<td>小米</td>
<td>¥4999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck">
</td>
<td>小米电视</td>
<td>小米</td>
<td>¥5999</td>
</tr>
</table>
<script>
// 1. 获取大复选框
const checkAll=document.querySelector('#checkAll')
// 2.获取所有的小复选框
const cks=document.querySelectorAll('.ck')
// 3.点击大复选框 注册事件
checkAll.addEventListener('click',function(){
//得到当前大复选框的选中状态
//console.log(checkAll.checked)//得到是true或者是false
//4. 遍历所有的小复选框 让复选框所有的checked=大复选框的checked
for(let i=0;i<cks.length;i++){
cks[i].checked=checkAll.checked;//chexkedAll也可写成this
}
})
</script>
</body>
</html>
全选反选案例2
需求:用户点击全选,则下面复选框全部选择,取消全选则全部取消,文字对应变化
分析:
- 遍历下面所有的checked,添加点击事件
- 检查小复选框选中的个数,是不是等于小复选框总的个数
- 把结果给全选按钮
- 利用css复选框选择器 input:checked
// 5.小复选框控制大复选框
for(let i=0;i<cks.length;i++){
// 5.1给所有的小复选框添加点击事件
// 判断选中的小复选框个数 是不是等于 总的小复选框个数
// 一定要写到点击里面 因为每次都要获得最新的个数
cks[i].addEventListener('click',function(){
// console.log(document.querySelectorAll('.ck:checked').length===cks.length)
checkAll.checked=document.querySelectorAll('.ck:checked').length===cks.length
})
}
事件流
- 事件流指的是事件完整执行过程中的流动路径
- 说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段
- 简单来说:捕获阶段是从父到子,冒泡阶段是从子到父
- 实际工作都是使用事件冒泡为主
事件捕获
- 事件捕获概念:从DOM的根元素开始执行对应的事件(从外到里)
- 事件捕获需要写对应的代码才能看到效果
- 代码:
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
- 说明:addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
- 若传入false代表冒泡阶段触发,默认就是false
- 若是用L0事件监听,则只有冒泡阶段,没有捕获
事件冒泡
概念:当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发,这一过程被称为事件冒泡
- 简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
- 事件冒泡是默认存在的
- L2事件监听第三个参数是flase,或者默认都是冒泡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.father{
width: 500px;
height: 500px;
background-color: pink;
}
.son {
width: 200px;
height: 200px;
background-color:purple;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
const fa=document.querySelector('.father')
const son=document.querySelector('.son')
document.addEventListener('click',function(){
alert('我是爷爷')
})
fa.addEventListener('click',function(){
alert('我是爸爸')
})
son.addEventListener('click',function(){
alert('我是儿子')
})
// DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
</script>
</body>
</html>
上面代码在鼠标点击儿子之后,会先弹出”我是儿子“,点击确定之后,会再次自动弹出”我是爸爸“,之后是”我是爷爷“
阻止冒泡
问题:因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
需求:若想把事件就限制在当前元素内,就需要阻止事件冒泡
前提:阻止事件冒泡需要拿到事件对象
语法:
事件对象.stoPropagation()
const fa=document.querySelector('.father')
const son=document.querySelector('.son')
document.addEventListener('click',function(){
alert('我是爷爷')
})
fa.addEventListener('click',function(){
alert('我是爸爸')
})
son.addEventListener('click',function(e){
alert('我是儿子')
e.stopPropagation()
})
给儿子添上阻止冒泡,父亲和爷爷就不会弹出来
注意: 此方法可以阻断时间流动传播,不光在冒泡阶段有效,捕获阶段也有效
解绑事件
on事件方式,直接使用null覆盖就可以实现事件的解绑
语法:L0事件移除解绑
const btn=document.querySelector('.btn')
//绑定事件
btn.onclick=function(){
alert('点击了')
}
// L0 事件移除解绑
// btn.onclick=null
addEventListener 方式,必须使用:
removeEventListener(事件类型,事件处理函数,[获取捕获或者冒泡阶段])
例如:
function fn(){
alert('点击了')
}
btn.addEventListener('click',fn)
//L2 事件移除解绑
btn.removeEventListener('click',fn)
注意:匿名函数不可被解绑
鼠标经过事件:
- mouseover和mouseout会有冒泡效果
- mouseenter和mouseleave 没有冒泡效果(推荐)
const dad=document.querySelector('.dad')
const baby=document.querySelector('.baby')
dad.addEventListener('mouseover',function(){
console.log('爸爸经过')
})
dad.addEventListener('mouseout',function(){
console.log('爸爸离开')
})
baby.addEventListener('mouseover',function(){
console.log('儿子经过')
})
baby.addEventListener('mouseout',function(){
console.log('儿子离开')
})
两种注册事件的区别
传统on注册(L0)
- 同一个对象,后面注册的事件就会覆盖前面注册(同一个事件)
- 直接使用null覆盖就可以实现事件的解绑
- 都是冒泡阶段执行的
事件监听注册(L2)
- 语法:addEventListener(事件类型,事件处理函数,是否使用捕获)
- 后面注册的事件不会覆盖前面注册的事件(同一个事件)
- 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
- 必须使用removeEventLister(事件类型,事件处理函数,获取捕获或者冒泡阶段)
- 匿名函数无法被解绑
事件委托
事件委托是利用事件流的特征解决一些开发需求的知识技巧
- 优点:减少注册次数,可以提高程序性能
- 原理:事件委托其实是利用事件冒泡的特点。
给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>第1个孩子</li>
<li>第2个孩子</li>
<li>第3个孩子</li>
<li>第4个孩子</li>
<li>第5个孩子</li>
<p>我不需要变色</p>
</ul>
<script>
//点击每个小li,当前li 文字变为红色
//按照事件委托的方式 委托给父级 事件写到父级身上
//1.获得父元素
const ul=document.querySelector('ul')
ul.addEventListener('click',function(e){
// console.log(e)//e是点击的事件对象
// e.target.style.color='red'//e.rarget指的是点击的具体元素标签
// 需求:只要点击li才会有效果
if(e.target.tagName==='LI'){
e.target.style.color='red'//e.rarget指的是点击的具体元素标签
}
})
</script>
</body>
</html>
tab栏切换改造(改为事件委托写法)
<!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>tab栏切换</title>
<style>
* {
margin: 0;
padding: 0;
}
.tab {
width: 590px;
height: 340px;
margin: 20px;
border: 1px solid #e4e4e4;
}
.tab-nav {
width: 100%;
height: 60px;
line-height: 60px;
display: flex;
justify-content: space-between;
}
.tab-nav h3 {
font-size: 24px;
font-weight: normal;
margin-left: 20px;
}
.tab-nav ul {
list-style: none;
display: flex;
justify-content: flex-end;
}
.tab-nav ul li {
margin: 0 20px;
font-size: 14px;
}
.tab-nav ul li a {
text-decoration: none;
border-bottom: 2px solid transparent;
color: #333;
}
.tab-nav ul li a.active {
border-color: #e1251b;
color: #e1251b;
}
.tab-content {
padding: 0 16px;
}
.tab-content .item {
display: none;
}
.tab-content .item.active {
display: block;
}
</style>
</head>
<body>
<div class="tab">
<div class="tab-nav">
<h3>每日特价</h3>
<ul>
<li><a class="active" href="javascript:;" data-id="0">精选</a></li>
<li><a href="javascript:;" data-id="1">美食</a></li>
<li><a href="javascript:;" data-id="2">百货</a></li>
<li><a href="javascript:;" data-id="3">个护</a></li>
<li><a href="javascript:;" data-id="4">预告</a></li>
</ul>
</div>
<div class="tab-content">
<div class="item active"><img src="./images1/tab00.png" alt="" /></div>
<div class="item"><img src="./images1/tab01.png" alt="" /></div>
<div class="item"><img src="./images1/tab02.png" alt="" /></div>
<div class="item"><img src="./images1/tab03.png" alt="" /></div>
<div class="item"><img src="./images1/tab04.png" alt="" /></div>
</div>
</div>
<script>
// // 1.a 模块制作 要给5个链接绑定鼠标经过事件
// // 1.1获取a元素
// const as=document.querySelectorAll('.tab-nav a')
// console.log(as)
// for(let i=0;i<as.length;i++){
// // console.log(as[i])
// as[i].addEventListener('mouseenter',function(){
// // console.log('鼠标经过')
// //排他思想
// // 先去除类名active
// document.querySelector('.tab-nav .active').classList.remove('active')
// // 添加类名active
// this.classList.add('active')
// //下面5个大盒子一一对应 .item
// document.querySelector('.tab-content .active').classList.remove('active')
// // 对应序号的那个item显示添加 active类
// document.querySelector(`.tab-content .item:nth-child(${i+1})`).classList.add('active')
// })
// }
/
//采取事件委托的形式 tab栏切换
//1. 获取ul 父元素 因为ul只有一个
const ul=document.querySelector('.tab-nav ul')
const items=document.querySelectorAll('.tab-content .item')
//2.添加事件
ul.addEventListener('click',function(e){
//console.log('e.target') //e.target是我们点击的对象
// 我们只有点击了a才会进行添加类和删除类操作
// console.log(e.target.tagName)
if(e.target.tagName==='A'){
// console.log('我选的是a')
// 排他思想 先移除原来的active 当前元素添加 active
document.querySelector('.tab-nav .active').classList.remove('active')
//当前元素添加active
// this指向ul 不能指代li
e.target.classList.add('active')
//下面大盒子模块
// console.log(e.target.dataset.id)
const i=+e.target.dataset.id//注意接收的值为数值型,接收回来的是字符型
//排他思想 先移除active
document.querySelector('.tab-content .active').classList.remove('active')
//对应的大盒子 添加 active
// document.querySelector(`.tab-content .item:nth-child(${i+1})`).classList.add('active')
items[i].classList.add('active')
// console.log(document.querySelector(`.tab-content .item:nth-child(${i+1})`))
}
})
</script>
</body>
</html>
小tip
自定义属性:
<div data-id="0"></div> <script> const div =document.querySelector('div') console.log(div.dataset.id)//0 </script>
阻止默认行为
在某些情况下需要阻止默认行为的发生,比如阻止链接的跳转,表单域跳转
语法:
<form action="http://www.itcast.cn">
<input type="submit" value="免费注册">
</form>
<a href="http://www.baidu.com">百度一下</a>
<script>
const form=document.querySelector('form')
form.addEventListener('submit',function(e){
//阻止默认行为 提交
e.preventDefault()
})
const a=document.querySelector('a')
a.addEventListener('click',function(e){
e.preventDefault()
})
</script>