EP063. “键盘快捷键与禁止背景滚动”
🔒 登录后可标记已读📌 并入 EP062(Preventing the Text Field Suggestions Pop-up): 作者提醒,浏览器自带的「输入历史自动补全建议」弹窗跟自定义的搜索 overlay 放一起看起来很别扭,如果不想要这个原生建议弹窗,可以给搜索的 <input> 元素加上 autocomplete="off" 这个属性。这是一句话的小技巧,没有配套操作步骤,也没有 -end 代码快照能对照(对照过 47/48/49 三个 -end 代码夹的 footer.php,都没有实际加上这个属性),本笔记只记录这个知识点,实际要不要加、加不加得上以你自己项目为准。
继续给 Search.js 加两个体验细节:① overlay 打开时锁住背景页面不让滚动,关闭时恢复;② 加键盘快捷键——按 S 键打开 overlay,按 Esc 键关闭。做键盘快捷键的过程中顺带讲了 keyup vs keydown 的区别,以及为什么要在 constructor 里额外记录一个「overlay 是否已打开」的状态,而不是每次都去读 DOM 判断。
涉及文件
wp-content/themes/fictional-university-theme/src/modules/Search.js(修改)
代码实现
// wp-content/themes/fictional-university-theme/src/modules/Search.js
class Search {
constructor() {
this.openButton = $(".js-search-trigger")
this.closeButton = $(".search-overlay__close")
this.searchOverlay = $(".search-overlay")
this.isOverlayOpen = false // 新增:记录 overlay 当前开关状态
this.events()
}
events() {
this.openButton.on("click", this.openOverlay.bind(this))
this.closeButton.on("click", this.closeOverlay.bind(this))
$(document).on("keydown", this.keyPressDispatcher.bind(this)) // 新增:全局监听键盘事件
}
// 新增:根据按下的键码决定要不要开关 overlay
keyPressDispatcher(e) {
if (e.keyCode == 83 && !this.isOverlayOpen) {
this.openOverlay()
}
if (e.keyCode == 27 && this.isOverlayOpen) {
this.closeOverlay()
}
}
openOverlay() {
this.searchOverlay.addClass("search-overlay--active")
$("body").addClass("body-no-scroll") // 新增:打开时禁止背景页面滚动
console.log("our open method just ran") // 新增:调试用,确认方法确实执行
this.isOverlayOpen = true // 新增
}
closeOverlay() {
this.searchOverlay.removeClass("search-overlay--active")
$("body").removeClass("body-no-scroll") // 新增:关闭时恢复滚动
console.log("our close method just ran") // 新增:调试用,确认方法确实执行
this.isOverlayOpen = false // 新增
}
}
export default Search
要点:
body-no-scroll这个 CSS class(overflow: hidden)在更早的讲座里就已经写进search-overlay.scss了,这一讲只是在 JS 里对<body>加/减这个 class。- 键盘监听绑在
$(document)上而不是某个具体元素,因为「按键」这个事件不需要限定在某个元素被点击/聚焦的前提下,整个页面任何地方按键都要能响应。 - 每个键盘按键都有一个数字
keyCode:S是 83,Esc是 27。判断方式是在事件回调的参数(e)里读e.keyCode,可以用console.log(e.keyCode)自己试出任意按键的编码。 keyup(松开键才触发一次)和keydown(按住不放会连续触发多次)是有区别的:作者一开始想用keyup,后来测试发现按住不放会有点「延迟感」,改成keydown立即响应,但keydown按住不放会不断重复触发方法。为了避免按住一个键就疯狂重复调用openOverlay/closeOverlay,才在 constructor 里加了this.isOverlayOpen这个状态属性:只有「当前是关的」才允许打开,只有「当前是开的」才允许关闭,重复触发时条件不满足就什么都不做。- 作者特别强调:判断 overlay 是否已打开,宁可用一个普通 JS 属性(
this.isOverlayOpen)来记录状态,也不要用 jQuery 去读 DOM 上有没有search-overlay--active这个 class 来判断——读写 DOM 比读写 JS 变量慢得多,应该尽量避免。
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
$(document).on("keydown", handler) | jQuery | 监听整个页面范围内的键盘按下事件 |
e.keyCode | 事件对象属性 | 读取本次按键对应的数字编码,用来判断按的是哪个键 |
keydown vs keyup | 键盘事件类型 | keydown 按下瞬间触发且会随长按重复触发;keyup 只在松开时触发一次 |
this.isOverlayOpen | 自定义属性(状态标记) | 记录 overlay 当前开关状态,避免重复触发同一方法,也避免频繁读 DOM |
常见坑
- 一开始把
"keyUp"写成大写 U(keyUp)导致事件完全不触发,jQuery 的事件名要全小写keyup/keydown。 - 用
keydown时如果不加「当前状态」判断,长按一个键会让openOverlay/closeOverlay被反复调用多次(虽然在这个场景下不会直接卡死浏览器,但是坏习惯,容易在更复杂功能里出问题)。 autocomplete="off"(EP062 提到的技巧)目前代码快照里没有实际加上,只是作者口头提醒,视需要自行加到搜索<input>上。
延伸 / 后续讲座会用到
this.isOverlayOpen 这个状态属性后面会继续在 EP065 里被用来判断「按 S 键时如果有其他输入框正在被聚焦就不要打开 overlay」的逻辑。计时器相关的功能(管理输入时的等待时间)会在下一讲 EP064 开始写。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 13, EP062, EP063