主题
2-3定时器和及轮播图定时切换案例
本页对应 第二章WebAPIs,共 4 段视频,约 43 分钟。
学习目标
- 能够使用
setInterval开启间隔定时器,正确传入回调函数与毫秒间隔,并说明回调函数名后不加小括号的原因。 - 能够保存
setInterval返回的唯一 ID,并使用clearInterval按 ID 关闭指定定时器。 - 能够使用信号量索引依次获取数组中的轮播对象,并据此更新图片
src、文字内容、背景颜色和小圆点样式。 - 能够实现小圆点
active类切换,做到先移除旧项的active,再为当前项添加active,并保证默认第一项可正常初始化。 - 能够定位并修复轮播索引越界导致的
undefined报错,并使用if、三元表达式或取余运算实现最后一张无缝回到第一张。
知识点
从“自动执行”到“特定时机执行”
为什么需要:以前写的代码大多按顺序自动执行,但网页交互不是这样:用户不点击,就不该弹窗;鼠标不经过,就不该显示下拉菜单。代码要等到某个特定时机才执行,才符合真实交互。
怎么想:先承认“事件”是程序运行时发生的特定动作或特定事情,例如点击按钮、鼠标经过菜单。事件发生后,我们才做对应的事情,例如点击按钮弹出警示框、鼠标经过某个盒子显示下拉菜单。
怎么做:把“要做什么”写成事件处理函数,再把它注册到元素对象上。这个注册过程就是事件监听,也叫事件注册、事件绑定。
易错点:不要把事件监听写成页面一打开就执行;它只是先注册,等事件触发时才执行。
事件监听三要素与基本语法
为什么需要:只写一个函数还不够,必须明确“谁被触发、什么情况下触发、触发后做什么”。
怎么想:事件监听三要素是事件源(谁被触发了)、事件类型(点击还是鼠标经过等)、事件处理函数(要做什么事情)。语法是:
JavaScript
元素对象.addEventListener('事件类型', 事件处理函数)怎么做:以“点击按钮弹出秋香”为例,先获取按钮,再注册 click 事件:
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>
</head>
<body>
<button class="btn">唐伯虎</button>
<script>
// 需求: 点击button按钮,页面会弹出一个警示框,内容显示 '秋香'
// 事件监听语法:
// 元素对象.addEventListener('事件类型', 事件处理函数)
// 1. 获取元素对象 button按钮
const btn = document.querySelector('.btn')
// 2. 事件监听
btn.addEventListener('click', function () {
alert('秋香')
})
</script>
</body>
</html>易错点:事件类型要加引号,并且小写;函数是点击之后再去执行,每次点击都会执行一次,不是注册时执行一次。
回调函数:把函数交给别人“回头调用”
为什么需要:事件处理函数不是立刻执行,而是先交给浏览器“记住”,等点击发生再调用。定时器也一样:转写稿里反复强调“每隔一段时间自动回头调用函数”,这个“回头调用”的函数就是回调函数。
怎么想:当一个函数被当作参数传递给另一个函数时,这个函数就是回调函数。它的作用是完成某些特定任务。事件监听里第二个参数是函数,定时器第一个参数也是函数,它们都是回调函数。
怎么做:
html
<script>
// 1. 定时器间隔函数,里面第一个参数又是函数,这个匿名函数就是回调函数
setInterval(function () {
console.log('我是回调函数')
}, 1000)
// 2. addEventListener 函数的第二个参数也是函数,这个匿名函数也是回调函数
btn.addEventListener('click', function () {
console.log('我是回调函数')
})
</script>转写稿在讲 setInterval 时有一个关键调试结论:函数名直接写在参数位置时,不要加小括号,因为定时器会按间隔“自动回头调用”;如果加了小括号,就变成先调用函数、把返回值传进去。事件监听同理,addEventListener('click', function () { ... }) 里的匿名函数不会立即执行,而是点击后由浏览器调用。
易错点:不要把“函数声明/函数名”和“函数调用”混为一谈;回调函数里的代码执行次数由事件触发次数或定时器间隔决定。
DOM0 与 DOM2 事件监听版本
为什么需要:事件监听有历史写法,不同写法在“同名事件是否覆盖”上表现不同,需要知道推荐哪一种。
怎么想:DOM0 写法是“事件源.on事件类型 = 函数”;DOM2 写法是 addEventListener。按笔记结论:on 方式同名事件会被覆盖,addEventListener 则不会,同时拥有事件更多特性,所以推荐使用 DOM2。
怎么做:
javascript
btn.onclick = function () {
alert('我是弹窗1')
}javascript
btn.addEventListener('click', function () {
console.log('我是回调函数')
})易错点:onclick 这种写法再赋一个同名事件,会把前面的覆盖掉;addEventListener 的事件类型写 'click',不要写成 'onclick'。调试时可以先用 console.log 确认回调是否被触发,再写弹窗或页面修改逻辑。
事件类型总览
事件类型是“用户做了什么、页面发生了什么”的名字。写交互时,先判断动作属于哪一类,再选对应事件名。事件类型字符串大小写敏感,统一用小写,例如 click 不能写成 Click。本节把常见类型分为鼠标事件、键盘事件、表单事件、焦点事件等,下面逐一展开。

说明:本节转写稿实际围绕定时器、轮播图展开,与“事件类型”不直接对应,不能硬套出事件结论;可迁移的是调试习惯:先
console.log看是否触发,再看值的变化与执行顺序。转写稿中的“定视器/净视器”应纠正为“定时器”,“缩引号”应纠正为“索引号”。
鼠标事件
为什么需要:页面最常响应用户的点击、移入、移出,例如按钮点击、卡片悬停提示。
怎么想:点击用 click;鼠标经过用 mouseenter;鼠标离开用 mouseleave。先获取元素,再绑定监听。
怎么做:
html
<body>
<div class="box"></div>
<script>
// 鼠标事件类型
const box = document.querySelector('.box')
// 1. 鼠标点击
box.addEventListener('click', function () {
console.log('我点击了盒子')
})
// 2. 鼠标经过
box.addEventListener('mouseenter', function () {
console.log('我鼠标经过了盒子')
})
// 3. 鼠标离开
box.addEventListener('mouseleave', function () {
console.log('我鼠标离开了盒子')
})
</script>
</body>易错点:事件名必须小写;mouseenter 与 mouseleave 要成对理解“进入/离开”,不要写成 mouseEnter。调试时打开控制台,分别点击、移入、移出盒子,看三条日志是否按动作出现。
焦点事件
为什么需要:表单需要知道用户是否正在输入,例如搜索框获得焦点时提示、失去焦点时校验。
怎么想:获得光标是 focus,失去光标是 blur;另外可用 元素.focus() 让元素自动获得焦点。
怎么做:
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>
[type=text] {
width: 245px;
height: 50px;
padding-left: 20px;
border: 1px solid #ccc;
font-size: 17px;
outline: none;
}
</style>
</head>
<body>
<input type="text" class="search-text">
<input type="text" class="search">
<script>
// 1. 焦点事件(手动触发)
const search_text = document.querySelector('.search-text')
// 1.1 获得焦点 focus
search_text.addEventListener('focus', function () {
console.log('获得了焦点')
})
// 1.2 失去焦点 blur
search_text.addEventListener('blur', function () {
console.log('失去了焦点')
})
// 2. 拓展 自动获得焦点 focus() 自动失去焦点 blur()
// 2.1 语法: 元素.focus() 比如百度首页搜索框自动获得焦点
const search = document.querySelector('.search')
search.focus()
</script>
</body>
</html>易错点:focus/blur 是事件名,focus()/blur() 是方法,别混写;自动聚焦要放在元素已获取之后。调试时先点第一个输入框看“获得”,再点空白看“失去”,刷新页面观察第二个输入框是否自动聚焦。
键盘事件和 input 事件
为什么需要:评论框、搜索框常要实时获取用户输入,或判断按键时机。
怎么想:按键动作看 keydown/keyup;表单 value 变化看 input。笔记表格给出关键差异:
| 事件 | 触发时机 | 得到表单值 |
|---|---|---|
| keydown | 按下键盘时触发 | 不带最后一次按键值 ab |
| keyup | 弹起键盘时触发 | 输入内容 abc |
| input | 表单value发生变化时触发 | 输入内容 abc |
怎么做:
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>input事件和键盘事件</title>
<style>
textarea {
width: 300px;
height: 30px;
padding: 10px;
border-color: transparent;
outline: none;
resize: none;
background: #f5f5f5;
border-radius: 4px;
}
</style>
</head>
<body>
<textarea id="tx" placeholder="发一条友善的评论" rows="2"></textarea>
<script>
// 获取元素
const tx = document.querySelector('#tx')
// 1. 键盘事件
// 1.1 键盘按下事件 keydown 当我们按下键盘的时候就触发
tx.addEventListener('keydown', function () {
console.log('我是keydown事件' + tx.value)
})
// 1.2 键盘弹起事件 keyup 当我们键盘弹起的时候就触发
tx.addEventListener('keyup', function () {
console.log('我是keyup事件' + tx.value)
})
// 2. 用户输入事件 input ,是表单value的值发生变化的时候触发
tx.addEventListener('input', function () {
console.log('我是input事件' + tx.value)
})
// 3. 注意事项
// 3.1 执行顺序 keydown → input → keyup
// 3.2 keydown 获取值的时候得不到最后一次按键的值, keyup和input可以得到用户输入内容
</script>
</body>
</html>易错点:执行顺序是 keydown → input → keyup;keydown 里读 value 往往少最后一次按键,keyup 和 input 才能拿到完整输入。调试时在 textarea 输入 abc,看控制台日志顺序和每次打印的值,就能验证表格结论。
课件图示








代码示例
示例 1:事件监听 + 常见事件类型(鼠标 / 焦点 / 键盘 / input)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件监听与常见事件类型</title>
<style>
.box {
width: 200px;
height: 100px;
line-height: 100px;
text-align: center;
background-color: pink;
cursor: pointer;
}
[type=text] {
width: 245px;
height: 50px;
padding-left: 20px;
border: 1px solid #ccc;
font-size: 17px;
outline: none;
}
textarea {
width: 300px;
height: 30px;
padding: 10px;
border-color: transparent;
outline: none;
resize: none;
background: #f5f5f5;
border-radius: 4px;
}
</style>
</head>
<body>
<button class="btn">唐伯虎</button>
<div class="box">鼠标经过我</div>
<input type="text" class="search-text" placeholder="请输入内容">
<textarea id="tx" placeholder="发一条友善的评论" rows="2"></textarea>
<script>
// ========== 1. 事件监听三要素:事件源 + 事件类型 + 事件处理函数 ==========
// 需求:点击 button 按钮,弹出警示框,内容显示 '秋香'
const btn = document.querySelector('.btn')
btn.addEventListener('click', function () {
alert('秋香')
})
// ========== 2. 鼠标事件 ==========
const box = document.querySelector('.box')
box.addEventListener('mouseenter', function () {
console.log('我鼠标经过了盒子')
})
box.addEventListener('mouseleave', function () {
console.log('我鼠标离开了盒子')
})
// ========== 3. 焦点事件(针对表单获得 / 失去光标) ==========
const search_text = document.querySelector('.search-text')
search_text.addEventListener('focus', function () {
console.log('获得了焦点')
})
search_text.addEventListener('blur', function () {
console.log('失去了焦点')
})
// ========== 4. 键盘事件和 input 事件 ==========
const tx = document.querySelector('#tx')
tx.addEventListener('keydown', function () {
console.log('我是keydown事件' + tx.value)
})
tx.addEventListener('input', function () {
console.log('我是input事件' + tx.value)
})
tx.addEventListener('keyup', function () {
console.log('我是keyup事件' + tx.value)
})
</script>
</body>
</html>关键行与易错点
元素对象.addEventListener('事件类型', 事件处理函数):三个要素缺一不可,事件源用querySelector先拿到。- 事件类型必须加引号且全小写,写成
'click',不是'Click'、更不是click变量。 - 函数体里的代码不是立即执行,是点击 / 经过 / 输入之后才“回头调用”,每触发一次执行一次——这就是回调函数。
mouseenter/mouseleave是“经过 / 离开”;focus/blur是“获得 / 失去焦点”,别和click混用。- 键盘三件套执行顺序是 keydown → input → keyup;
keydown里读tx.value拿不到最后一次按键的值,keyup和input才能拿到完整内容。 - 对比 DOM0 写法
btn.onclick = function(){}:同名事件会被覆盖,addEventListener不会覆盖,推荐后者。
示例 2:定时器间隔函数(开启 / 关闭 / 回调函数)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>定时器间隔函数</title>
</head>
<body>
<button class="stop">关闭定时器</button>
<script>
// 1. 回调函数:把函数写到外面,再当作参数传给 setInterval
// 注意:传函数名 repeat 时,后面不加小括号!
function repeat() {
console.log('我是一秒钟自动执行一次的函数')
}
// 2. 开启定时器:setInterval(函数, 间隔时间)
// 间隔时间单位是毫秒,1000 毫秒 = 1 秒
// 开启后返回一个唯一的 ID 数字,页面中第一个定时器返回 1
let timer = setInterval(repeat, 1000)
console.log(timer) // 1
// 3. 关闭定时器:clearInterval(定时器ID)
// 想关掉定时器,必须先用一个变量把 ID 存起来
document.querySelector('.stop').addEventListener('click', function () {
clearInterval(timer)
console.log('定时器已关闭')
})
</script>
</body>
</html>关键行与易错点
setInterval(function(){}, 1000)里的匿名函数就是回调函数,定时器每隔指定时间自动“回头调用”它一次,永不停歇。- 函数名后面不加小括号:
setInterval(repeat, 1000)是对的;写成setInterval(repeat(), 1000)会立刻执行一次并把返回值传进去,定时器就废了。 - 间隔时间单位是毫秒,1 秒要写
1000,写成1就是 1 毫秒。 - 开启定时器会返回一个唯一 ID(1、2、3…),页面里多个定时器靠它区分,避免关错。
- 关闭定时器必须拿到变量名:
clearInterval(timer);如果写成let timer = setInterval(...)后马上clearInterval(timer),代码执行太快,你几乎看不到输出——实际开发中都是满足某个条件(如鼠标经过、倒计时结束)才关。
示例 3:综合案例 —— 轮播图定时版
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮播图定时版</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
ul { list-style: none; }
.slider {
position: relative;
width: 600px;
height: 400px;
margin: 50px auto;
overflow: hidden;
}
.slide-wrapper img {
display: block;
width: 100%;
height: 400px;
object-fit: cover;
}
.slide-photo {
position: absolute;
left: 0;
bottom: 60px;
width: 100%;
text-align: center;
color: #fff;
font-size: 22px;
}
.footer {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
background-color: #ffc0cb;
transition: background-color .3s;
}
.footer li {
width: 12px;
height: 12px;
border-radius: 50%;
background-color: #fff;
}
.footer li.active { background-color: #e93b3d; }
</style>
</head>
<body>
<div class="slider">
<div class="slide-wrapper">
<img src="https://picsum.photos/seed/1/600/400" alt="">
<p class="slide-photo">第一张图片</p>
</div>
<ul class="footer">
<!-- 第一个小 li 的 active 类不能删,页面刷新时默认选中它 -->
<li class="active"></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<script>
// ========== 0. 数据 ==========
const slideData = [
{ url: 'https://picsum.photos/seed/1/600/400', title: '第一张图片', color: '#ffc0cb' },
{ url: 'https://picsum.photos/seed/2/600/400', title: '第二张图片', color: '#a0d8ef' },
{ url: 'https://picsum.photos/seed/3/600/400', title: '第三张图片', color: '#b5e6b5' },
{ url: 'https://picsum.photos/seed/4/600/400', title: '第四张图片', color: '#ffe4a0' },
{ url: 'https://picsum.photos/seed/5/600/400', title: '第五张图片', color: '#d8c0ff' },
{ url: 'https://picsum.photos/seed/6/600/400', title: '第六张图片', color: '#ffc8a0' },
{ url: 'https://picsum.photos/seed/7/600/400', title: '第七张图片', color: '#a0e0d8' },
{ url: 'https://picsum.photos/seed/8/600/400', title: '第八张图片', color: '#f0b0c0' }
]
// ========== 1. 获取元素(只获取一次,放在定时器外面) ==========
const img = document.querySelector('.slide-wrapper img')
const p = document.querySelector('.slide-photo')
const footer = document.querySelector('.footer')
// ========== 2. 信号量:控制播放第几张,必须用 let,初始值为 0 ==========
let i = 0
// ========== 3. 开启定时器,按序自动播放 ==========
setInterval(function () {
// 3.1 信号量加加
i++
// 3.2 播放到最后一张后自动回到第一张(无缝衔接)
// if 写法:if (i >= slideData.length) i = 0
// 三元写法:i = i >= slideData.length ? 0 : i
// 取余写法(最简洁):
i = i % slideData.length
// 3.3 依次拿到数组中的下一个对象
const obj = slideData[i]
// 3.4 利用对象更换图片、文字、背景颜色
img.src = obj.url
p.innerText = obj.title
footer.style.backgroundColor = obj.color
// 3.5 更换小圆点:必须在定时器里面获取,因为每次操作的是不同的小 li
// 先移除以前的 active(注意 querySelector 选类名要加点)
document.querySelector('.footer .active').classList.remove('active')
// 再给当前的 li 添加 active(classList 里不加点)
footer.children[i].classList.add('active')
}, 1000)
</script>
</body>
</html>关键行与易错点
- 信号量
let i = 0:只能用let(后面要i++重新赋值),const会报错;从 0 开始是因为页面刷新已经显示第一张,1 秒后要切到第二张(索引 1)。 - 获取元素放定时器外面:定时器每秒执行一次,把
img、p、footer写进去等于每秒重新获取一次,完全没必要。 - 小圆点必须在定时器里面获取:前面是“改属性”,只需要一个对象;小圆点每次要操作的是不同的小 li,所以
footer.children[i]要写在定时器内。 - 顺序不能颠倒:先
document.querySelector('.footer .active').classList.remove('active'),再footer.children[i].classList.add('active')。反了就会出现两个红点。 - 加点与不加点的区别:
querySelector('.footer .active')是按类名选择,要加点;classList.remove('active')/add('active')是操作类名,不加点。 - 第一个 li 的
active类不能删:页面刷新时默认选中第一个,若删了,第一次querySelector('.footer .active')就选不到元素会报错。 - 归零位置在
i++之后、使用i之前:写成if (i >= 8) i = 0会漏掉最后一张(等于 7 时第八章还没播就被重置);应该是i >= slideData.length,或者直接i = i % slideData.length取余,且用slideData.length而不是写死 8,数组增减不用改代码。
常见错误
1. 定时器第一个参数写成 repeat()
- 现象:回调只跑了一次就再也不执行,或控制台报
undefined is not a function。 - 原因:加括号是立刻调用并把返回值(
undefined)交给定时器,传进去的不是函数本身。 - 修法:只写函数名
setInterval(repeat, 1000);必须传参时用() => repeat(x)包一层。
2. 事件类型写成 'onclick' / 'Click'
- 现象:点击毫无反应,控制台也不报错,最难查。
- 原因:
addEventListener的事件类型是不带 on、全小写的字符串;onclick是 DOM0 的属性名,不是事件类型。 - 修法:统一写
'click'、'mouseenter'、'keyup';写完顺手检查引号和大小写。
3. 用 keydown 取输入框的值,总是少最后一个字符
- 现象:输入
abc,日志依次是''、'a'、'ab'。 - 原因:
keydown触发时本次按键的值还没写进value,这是时序问题,不是代码写错。 - 修法:要完整内容改用
input或keyup;只有确实需要"按键按下"这一时机才用keydown。
4. 索引一直自增,播到最后一张就报错
- 现象:轮播到第 8 张后控制台报
Cannot read properties of undefined (reading 'url'),画面卡死。 - 原因:
i++无限增长,超出数组长度后arr[i]是undefined,再取属性必然崩。 - 修法:在自增语句紧后面做复位,如
i = i % arr.length;复位必须先于"用 i 取数据"执行,否则会漏播最后一张。
5. 小圆点越切越多,或切到后面就全灭
- 现象:几个圆点同时高亮;或从第二个开始,一个都不亮。
- 原因:只
add('active')没remove旧的;或把"获取当前小圆点"的代码提到了定时器外面,永远操作同一个元素。 - 修法:先
querySelector('.active')移除,再给当前项添加;获取小圆点必须写在定时器内部(依赖当次索引),并且 HTML 里要保留一个初始active。
6. 想停定时器却停不下来
- 现象:
clearInterval()传了空或传错,定时器照跑。 - 原因:开启时没接返回值,拿不到那个唯一 ID。
- 修法:
const timer = setInterval(...),关闭时clearInterval(timer);多个定时器各用各的变量名,别混用。
7. 索引用 const 声明后自增报错
- 现象:
Assignment to constant variable。 - 原因:
const声明的变量不可重新赋值,而i++本质是重新赋值。 - 修法:会变的索引用
let;只有确实不变的元素引用才用const。
练习
练习 1|不覆盖的多次绑定 给同一个按钮绑定两个 click 回调,分别打印 A 和 B,要求点击一次两条都输出;再用 onclick 写一遍,观察差异并说明原因。
练习 2|实时字数统计 文本框输入时实时显示"已输入 n / 20",超过 20 字把计数变红。要求:分别用 keydown 和 input 各实现一次,对比同一串输入下计数是否一致,并说出你最终选哪个。
练习 3|搜索框交互 页面加载后搜索框自动获得焦点;获得焦点时边框变蓝,失去焦点时若内容为空则边框变灰并提示"请输入关键词"。要求三个行为分别绑定,互不影响。
练习 4|可停止的倒计时 用 setInterval 实现从 10 倒数到 0,到 0 时停止并在页面显示"时间到"。要求:定时器 ID 必须存进变量;另加一个"暂停"按钮也能停。
练习 5|索引复位三种写法 给定 i++ 后紧跟取 arr[i] 的代码,分别用 if、三元、取余三种方式补上边界复位,跑通 8 张图的循环;再用一句话说明为什么复位语句不能写在取数据之后。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 定时器之间隔函数 | 11:17 |
| 2 | 综合案例-轮播图定时版-上 | 07:25 |
| 3 | 综合案例-轮播图定时版-中 | 11:53 |
| 4 | 综合案例-轮播图定时版-下 | 13:01 |
小结
- 事件监听统一用
addEventListener,事件类型是不带on的小写字符串,同名事件不会互相覆盖。 - 回调函数的核心是"传引用不传结果"——加不加括号,决定了它是被交出去等待调用,还是当场执行。
- 定时器第一个参数必须传函数本身,这是本节最高频的坑;传调用结果等于把
undefined交给定时器。 - 开定时器就必须接返回值,没有 ID 就没有关闭的资格;
clearInterval只能靠这个 ID 工作。 - 定时器内的代码会反复执行,元素查询能提到外面的就提,只有依赖当次索引的(如当前小圆点)才留在里面。
- 循环播放的本质是索引取模,复位语句必须紧跟在自增之后、使用之前,顺序错一步就漏一张或直接崩。
- 类名切换遵循"先清后加",HTML 里保留一个初始
active,否则第一次操作就可能对null调方法。 - 键盘相关事件按需求选:要完整输入内容用
input或keyup,keydown只适合"按键按下"这个时机本身。