web API
前言
变量声明
const优先,可变再改为let
原因:
- 语义化更好
- 若以后变量不改变,就应用const声明
- 实际开发中,react框架中基本都是从const
[!IMPORTANT]
基本变量中数据若改变,则不可用const
数组,对象等复杂数据类型即使内容改变,也可用const
本质
对象等再栈空间中存储的是地址,用const声明只可使地址指向无法改变,但堆空间中的内容依旧可以改变(但是不可以重新赋值)
基本认知
作用
使用js去操作html和浏览器
分类
- DOM(文档对象模型)
- BOM(浏览器对象模型)
DOM
什么是DOM
Document Object Model
用来呈现以及与任意HTML或XML文档交互的API(操作网页内容标签)
作用
开发网页内容特效和实现用户交互
DOM树
描述网页内容关系(最大是document对象,然后是HTML对象,然后再细分)
核心思想
把网页内容标签当作对象处理
DOM对象(important)
浏览器根据html标签生成的js对象,因此拥有属性和方法
获取DOM元素
根据css选择器
- 匹配一个
docment.querySelector('css选择器')
【若有多个,默认选第一个,没有符合的返回null】 - 匹配多个
document.querySelectorAll('css选择器')
【返回NodeList对象集合】 ==> 通过遍历修改
匹配多个得到的是伪数组,有长度,索引号,但没有数组方法
案例
ul li遍历
<body>
<ul class="dav">
<li>first</li>
<li>twice</li>
<li>third</li>
</ul>
<p id="a">1</p>
<script>
const arr = document.querySelectorAll('.dav li')
console.log(arr)
for (let i = 0; i < arr.length; i++) {
console.log(arr[i])
}
const b = document.querySelectorAll('#a')
b[0].style.color = 'red'
</script>
</body>
操作元素内容
修改元素文本
对象.innerText = '内容'
[不解析标签]
对象.innerHTML = '内容'
抽奖案例
<body>
<h2></h2>
<h3></h3>
<h4></h4>
<script>
//获取元素
const h2 = document.querySelector('h2')
const h3 = document.querySelector('h3')
const h4 = document.querySelector('h4')
let num
const arr = ['艾莎', '平顶', "哈希", "阿婆", "拉乌"]
num = Math.floor(Math.random() * arr.length)
h2.innerHTML = `一等奖:${arr[num]}`
arr.splice(num, 1)
num = Math.floor(Math.random() * arr.length)
h3.innerHTML = `二等奖:${arr[num]}`
arr.splice(num, 1)
num = Math.floor(Math.random() * arr.length)
h4.innerHTML = `三等奖:${arr[num]}`
arr.splice(num, 1)
</script>
</body>
随机数范围根据抽奖人数数组长度作变化
操作元素常用属性
对象.属性 = 值
应用场景: 当页面刷新时,图片随机切换
操作元素样式属性
- 通过style改属性 【如果属性有一连接符’-',需转为小驼峰命名[连接符后一个字母大写]】
- 通过类名className 【若本来有类名,不写会被覆盖】
- 通过classList
- add(类名) 追加类
- remove(类名)删除类
- toggle(类名)更换类 【有就删除,没有就照常添加】
[!IMPORTANT]
通过style改属性,生成的是行内样式
1.对象.style.属性 = 值
2.对象.className = '类名'
3.对象.classList.各类方法
轮播图案例
<!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="../轮播图素材/slider01.jpg" alt="" />
</div>
<div class="slider-footer">
<p>对人类来说会不会太超前了?</p>
<ul class="slider-indicator">
<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 sliderData = [
{ url: '../轮播图素材/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
{ url: '../轮播图素材/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
{ url: '../轮播图素材/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
{ url: '../轮播图素材/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
{ url: '../轮播图素材/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
{ url: '../轮播图素材/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
{ url: '../轮播图素材/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
{ url: '../轮播图素材/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
]
//2.获取一个随机数
const random = parseInt(Math.random() * sliderData.length)
//3.将数据渲染到标签上
//3.1.获取图片元素
const img = document.querySelector('.slider-wrapper img')
img.src = sliderData[random].url
// 4.将p里面的文字进行更换
// 4.1获取文字元素
const p = document.querySelector('.slider-footer p')
p.innerHTML = sliderData[random].title
//5.更改背景颜色
// 5.1获取设置背景颜色的元素
const bcc = document.querySelector('.slider-footer')
bcc.style.backgroundColor = sliderData[random].color
// 6.高亮对应的小圆点
const point = document.querySelector(`.slider-indicator li:nth-child(${random + 1})`)
point.classList.add('active')
</script>
</body>
</html>
实现效果:轮播图随机出现一张,文字,背景颜色,小圆点都改为对应的
操作表单元素属性
场景:密码框中常用的点击眼睛密码可见,本质就是表单的type属性有password改为了text
[!NOTE]
表单中的内容不可用innerHTML获取,要用value
表单中有些属性,存在就有效果,移除就没效果,可用布尔值来进行赋值
如disabled,selected,checked
可用不空的字符串赋值,可用,但不提倡
自定义属性data
在标签上一律以data开头,在DOM对象上一律以datasest对象方式获取
<body>
<div data-id="1" data-name="div">1</div>
<script>
//1.获取元素
const div = document.querySelector('div')
console.log(div.dataset);
</script>
定时器-间歇函数
(有两种,间歇函数写定时器是一种)
场景:用户协议同意,秒杀倒计时(有时需要关闭定时器)
开启
setInterval(函数名,间隔时间)
[有独一无二的id,需要用变量接收,关了再开id不一样]
clearInterval(num)
【num就是上面接收setInterval( )的变量】
案例
阅读用户协议
<!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>
<textarea name="" id="" cols="30" rows="10">
用户注册协议
欢迎注册成为京东用户!在您注册过程中,您需要完成我们的注册流程并通过点击同意的形式在线签署以下协议,请您务必仔细阅读、充分理解协议中的条款内容后再点击同意(尤其是以粗体或下划线标识的条款,因为这些条款可能会明确您应履行的义务或对您的权利有所限制)。
【请您注意】如果您不同意以下协议全部或任何条款约定,请您停止注册。您停止注册后将仅可以浏览我们的商品信息但无法享受我们的产品或服务。如您按照注册流程提示填写信息,阅读并点击同意上述协议且完成全部注册流程后,即表示您已充分阅读、理解并接受协议的全部内容,并表明您同意我们可以依据协议内容来处理您的个人信息,并同意我们将您的订单信息共享给为完成此订单所必须的第三方合作方(详情查看
</textarea>
<br>
<button class="btn" disabled>我已经阅读用户协议(5)</button>
<script>
//1.获取元素
const agree = document.querySelector('.btn')
//2.函数逻辑处理
let num = 5
let id = setInterval(function () {
if (num > 0) {
num--
agree.textContent = `我已经阅读用户协议(${num})`
}
if (num == 0) {
agree.textContent = '我同意此协议 '
agree.disabled = false
clearInterval(id)
}
}, 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="../轮播图素材/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>
</ul>
<div class="toggle">
<button class="prev"><</button>
<button class="next">></button>
</div>
</div>
</div>
<script>
// 1. 初始数据
const sliderData = [
{ url: '../轮播图素材/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
{ url: '../轮播图素材/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
{ url: '../轮播图素材/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
{ url: '../轮播图素材/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
{ url: '../轮播图素材/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
{ url: '../轮播图素材/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
{ url: '../轮播图素材/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
{ url: '../轮播图素材/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
]
//2.设置定时器及匿名函数
//设置一个轮播图的序号变量
let num = 1
let id = setInterval(function () {
//3.通过num++,实现下一张的轮播
num++
//2.当num等于8,就返回到原来的1
if (num === 8)
num = 1
//1.数据渲染到页面上
const img = document.querySelector('.slider-wrapper img')
img.src = sliderData[num - 1].url
const p = document.querySelector('.slider-footer p')
p.innerHTML = sliderData[num - 1].title
const bcc = document.querySelector('.slider-footer')
bcc.style.backgroundColor = sliderData[num - 1].color
//去除以前的 (只要找标签上有active类的就行了)
document.querySelector('.slider-indicator .active').classList.remove('active')
const point = document.querySelector(`.slider-indicator li:nth-child(${num})`)
point.classList.add('active')
}, 1000)
</script>
</body>
</html>
易错点:小圆点之前的高亮需要移除
事件监听
事件 — 系统发生的动作或事情
事件监听 — 事件被触发后,调用函数或其他行为进行响应
语法
元素对象.addEventListener('事件类型',函数)
三要素
- 事件源:什么元素被触发
- 事件类型: 用什么方式触发
- 事件调用的函数
案例
关闭广告
<!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>
.box {
position: relative;
width: 1000px;
height: 200px;
background-color: pink;
margin: 100px auto;
text-align: center;
font-size: 50px;
line-height: 200px;
font-weight: 700;
}
.box1 {
position: absolute;
right: 20px;
top: 10px;
width: 20px;
height: 20px;
background-color: skyblue;
text-align: center;
line-height: 20px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="box">
我是广告
<div class="box1">X</div>
</div>
<script>
//1.获取事件源
const box1 = document.querySelector('.box1')
//2.获取关闭对象
const box = document.querySelector('.box')
//3.监听点击事件并关闭
box1.addEventListener('click', function () {
// box.classList.remove('box')
// box.innerHTML = ''
box.style.display = 'none'
})
</script>
</body>
</html>
随机点名事件
<!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 = ['马超', '黄忠', '赵云', '关羽', '张飞']
//1.获取事件源
const start = document.querySelector('.start')
const end = document.querySelector('.end')
//1.2获取需要进行更改的对象
const qs = document.querySelector('.qs')
//2.监听点击事件并进行函数调用(附带计时器)
//2.0 随机数赋予的变量 定时器的id变量
let random
let clock
//2.1开始按钮监听事件
start.addEventListener('click', function () {
clock = setInterval(function () {
random = Math.floor(Math.random() * arr.length)
qs.innerHTML = arr[random]
}, 50)
})
//2.2结束按钮监听事件
end.addEventListener('click', function () {
clearInterval(clock)
arr.splice(random, 1)
//内置 增加限制条件 按钮禁用
if (arr.length === 1) {
start.disabled = true
end.disabled = true
}
})
setInterval(function () { console.log(arr.length); }, 3000)
</script>
</body>
</html>
事件监听版本
- DOM L0
对象.oncclick = 函数
- DOM L2
对象.addEventListener()
[现在写法]
鼠标监听
- 鼠标经过
mouseenter
- 鼠标离开
mouseleave
案例
轮播图完整版
需求:当点击左右按钮的时候,可以对应切换轮播图,同时可以自动播放,但会被鼠标的经过给打断
4个业务
- 右侧按钮
- 左侧按钮
- 自动播放
- 鼠标感应:经过暂停定时器,离开开启定时器
<!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="../轮播图素材/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 sliderData = [
{ url: '../轮播图素材/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
{ url: '../轮播图素材/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
{ url: '../轮播图素材/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
{ url: '../轮播图素材/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
{ url: '../轮播图素材/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
{ url: '../轮播图素材/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
{ url: '../轮播图素材/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
{ url: '../轮播图素材/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
]
//获取作用对象
const box = document.querySelector('.slider')
const img = document.querySelector('.slider-wrapper img')
const p = document.querySelector('.slider-footer p')
const bcc = document.querySelector('.slider-footer')
// 信息量
let i = 0
//渲染下一张轮播图的函数复用
function common() {
//1.4渲染数据到页面上
img.src = sliderData[i].url
p.innerHTML = sliderData[i].title
bcc.style.backgroundColor = sliderData[i].color
//1.5 更换小圆点 移除之前的小圆点的类名,添加后面的小圆点的类名
document.querySelector('.slider-indicator .active').classList.remove('active')
document.querySelector(`.slider-indicator li:nth-child(${i + 1})`).classList.add('active')
}
//1.右侧按钮
//1.1获取事件源
const next = document.querySelector('.next')
//1.2获取数据
// console.log(sliderData[i]);
//1.3绑定点击事件
next.addEventListener('click', function () {
//进行跳转
i++
//1.5当i>7时,让i == 0
if (i > sliderData.length - 1) {
i = 0
}
//调用函数
common()
})
//2.左侧按钮
//2.1获取事件源
const prev = document.querySelector('.prev')
//1.2获取数据
// console.log(sliderData[i]);
//1.3绑定点击事件
prev.addEventListener('click', function () {
//进行跳转
i--
//1.5当i<0时,让i = 7
if (i < 0) {
i = sliderData.length - 1
}
//调用函数
common()
})
//3.自动播放模块
let clock = setInterval(function () {
//利用js自动调用next的点击事件
next.click()
}, 1000)
//4.鼠标感应轮播图区域,关闭开启定时器
//4.1鼠标经过大盒子
box.addEventListener('mouseenter', function () {
//停止计时器
clearInterval(clock)
})
//4.2鼠标离开大盒子
box.addEventListener('mouseleave', function () {
//开启定时器
clock = setInterval(function () {
//利用js自动调用next的点击事件
next.click()
}, 1000)
})
</script>
</body>
</html>
焦点事件
表单获得光标
focus
获得焦点
blur
失去焦点
<script>
//获取事件源
const input = document.querySelector('input')
//绑定焦点事件
input.addEventListener('focus', function () {
console.log('获取焦点');
})
input.addEventListener('blur', function () {
console.log('失去焦点');
})
</script>
案例
小米搜索框
<!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 {
display: block;
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 list = document.querySelector('.result-list')
//1.获取事件源input
const input = document.querySelector('input')
//2.绑定焦点事件
//2.1获取焦点
input.addEventListener('focus', function () {
list.style.display = 'block'
input.classList.add('search')
})
//2.2失去焦点
input.addEventListener('blur', function () {
list.style.display = 'none'
input.classList.remove('search')
})
</script>
</body>
</html>