键盘交互是提升用户体验的重要一环。用户按回车提交表单、按 ESC 关闭弹窗、按上下键选择列表项...这些操作都需要监听特定的键盘按键。
Vue 提供了按键修饰符,让键盘事件监听变得简单直观。不需要在事件处理函数中判断
event.keyCode,直接在模板中声明要监听的按键即可。
传统方式监听回车键:
methods: {
handleKeyup: function(event) {
if (event.keyCode === 13) {
// 回车键被按下
this.submit()
}
}
}
使用按键修饰符:
<input @keyup.enter="submit">
简洁明了,一眼就能看出监听的是回车键。
Vue 为常用按键提供了别名:
| 修饰符 | 按键 | keyCode |
|---|---|---|
.enter | 回车键 | 13 |
.tab | Tab 键 | 9 |
.esc | ESC 键 | 27 |
.space | 空格键 | 32 |
.up | 上箭头 | 38 |
.down | 下箭头 | 40 |
.left | 左箭头 | 37 |
.right | 右箭头 | 39 |
.delete | 删除键(包括 Backspace 和 Delete) | 8 / 46 |
<div id="app">
<!-- 回车提交 -->
<input
type="text"
v-model="message"
@keyup.enter="sendMessage"
placeholder="按回车发送"
>
<!-- ESC 清空 -->
<input
type="text"
v-model="search"
@keyup.esc="clearSearch"
placeholder="按 ESC 清空"
>
<!-- 方向键导航 -->
<div
@keyup.up="selectPrev"
@keyup.down="selectNext"
tabindex="0"
>
使用上下键选择
</div>
<!-- 空格播放/暂停 -->
<div @keyup.space="togglePlay" tabindex="0">
按空格播放/暂停
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: '',
search: ''
},
methods: {
sendMessage: function() {
if (this.message.trim()) {
console.log('发送消息:', this.message)
this.message = ''
}
},
clearSearch: function() {
this.search = ''
},
selectPrev: function() {
console.log('选择上一个')
},
selectNext: function() {
console.log('选择下一个')
},
togglePlay: function() {
console.log('播放/暂停')
}
}
})
</script>
如果需要监听没有别名的按键,可以直接使用 keyCode:
<!-- 监听 F1 键(keyCode 112) -->
<input @keyup.112="showHelp">
<!-- 监听数字键 1(keyCode 49) -->
<input @keyup.49="selectFirst">
注意
直接使用 keyCode 已被 Web 标准废弃,不同键盘布局可能产生不同的 keyCode。推荐使用按键别名或自定义别名。
Vue 允许你为按键定义自定义别名:
// 全局定义按键别名
Vue.config.keyCodes = {
v: 86,
f1: 112,
mediaPlayPause: 179,
up: [38, 87] // 可以是数组,支持多个 keyCode
}
使用自定义别名:
<input @keyup.media-play-pause="togglePlay">
<input @keyup.f1="showHelp">
Vue 提供了系统修饰键,可以与其他按键组合使用:
| 修饰符 | 按键 | 说明 |
|---|---|---|
.ctrl | Ctrl 键 | |
.alt | Alt 键 | |
.shift | Shift 键 | |
.meta | Meta 键 | Mac 上是 ⌘,Windows 上是 ⊞ |
<div id="app">
<!-- Ctrl + S 保存 -->
<input @keyup.ctrl.s="save" placeholder="Ctrl+S 保存">
<!-- Ctrl + Enter 发送 -->
<textarea @keyup.ctrl.enter="send" placeholder="Ctrl+Enter 发送"></textarea>
<!-- Alt + N 新建 -->
<div @keyup.alt.n="createNew" tabindex="0">Alt+N 新建</div>
<!-- Shift + Enter 换行 -->
<textarea @keyup.shift.enter="newLine" placeholder="Shift+Enter 换行"></textarea>
<!-- Ctrl + Shift + S 另存为 -->
<input @keyup.ctrl.shift.s="saveAs" placeholder="Ctrl+Shift+S 另存为">
</div>
默认情况下,系统修饰键可以单独触发。比如 @keyup.ctrl 会在单独按下 Ctrl 时触发。
使用 .exact 修饰符可以精确控制组合键:
<!-- 只有 Ctrl 被按下时触发(不能同时按其他修饰键) -->
<button @click.ctrl.exact="handleCtrlClick">Ctrl + 点击</button>
<!-- 只有 Ctrl + Shift 被按下时触发 -->
<button @click.ctrl.shift.exact="handleCtrlShiftClick">Ctrl + Shift + 点击</button>
<!-- 没有任何修饰键时触发 -->
<button @click.exact="handleClick">普通点击</button>
<div class="search-box">
<input
type="text"
v-model="keyword"
@keyup.enter="search"
@keyup.esc="clearKeyword"
placeholder="输入关键词,回车搜索"
>
<button @click="search">搜索</button>
</div>
<script>
methods: {
search: function() {
if (!this.keyword.trim()) return
console.log('搜索:', this.keyword)
// 调用搜索 API
},
clearKeyword: function() {
this.keyword = ''
}
}
</script>
<div
class="app"
@keyup.ctrl.s="save"
@keyup.ctrl.z="undo"
@keyup.ctrl.y="redo"
@keyup.ctrl.shift.s="saveAs"
@keyup.esc="closeModal"
tabindex="0"
>
<div class="editor">
<textarea v-model="content"></textarea>
</div>
<div class="modal" v-if="showModal">
<p>弹窗内容</p>
<button @click="closeModal">关闭(ESC)</button>
</div>
</div>
<script>
new Vue({
el: '.app',
data: {
content: '',
showModal: false
},
methods: {
save: function() {
console.log('保存内容')
},
saveAs: function() {
console.log('另存为')
},
undo: function() {
console.log('撤销')
},
redo: function() {
console.log('重做')
},
closeModal: function() {
this.showModal = false
}
}
})
</script>
<div class="list-container" tabindex="0" @keyup="handleKeyNav">
<div
v-for="(item, index) in items"
:key="item.id"
:class="{ active: index === selectedIndex }"
@click="selectedIndex = index"
>
{{ item.name }}
</div>
</div>
<script>
new Vue({
data: {
items: [
{ id: 1, name: '选项一' },
{ id: 2, name: '选项二' },
{ id: 3, name: '选项三' },
{ id: 4, name: '选项四' }
],
selectedIndex: 0
},
methods: {
handleKeyNav: function(event) {
switch(event.key) {
case 'ArrowUp':
case 'Up':
if (this.selectedIndex > 0) {
this.selectedIndex--
}
break
case 'ArrowDown':
case 'Down':
if (this.selectedIndex < this.items.length - 1) {
this.selectedIndex++
}
break
case 'Enter':
this.selectItem(this.items[this.selectedIndex])
break
}
},
selectItem: function(item) {
console.log('选择了:', item.name)
}
}
})
</script>
<div
class="game-area"
tabindex="0"
@keyup.up="moveUp"
@keyup.down="moveDown"
@keyup.left="moveLeft"
@keyup.right="moveRight"
@keyup.space="jump"
>
<div class="player" :style="playerStyle"></div>
</div>
<script>
new Vue({
data: {
position: { x: 0, y: 0 }
},
computed: {
playerStyle: function() {
return {
transform: `translate(${this.position.x}px, ${this.position.y}px)`
}
}
},
methods: {
moveUp: function() {
this.position.y -= 10
},
moveDown: function() {
this.position.y += 10
},
moveLeft: function() {
this.position.x -= 10
},
moveRight: function() {
this.position.x += 10
},
jump: function() {
console.log('跳跃!')
}
}
})
</script>
tabindex 属性
非表单元素(如 div)默认无法获得焦点,需要添加 tabindex 属性才能响应键盘事件:
<div tabindex="0" @keyup.enter="handleEnter">
这个 div 可以获得焦点
</div>
按键冲突
避免与浏览器快捷键冲突。比如 Ctrl+S 默认会触发浏览器保存,需要阻止默认行为:
<div @keydown.ctrl.s.prevent="save">
Ctrl+S 保存(阻止浏览器默认行为)
</div>
按键修饰符让键盘事件监听变得简单:
.enter、.esc、.space 等常用按键.ctrl、.alt、.shift、.meta 组合使用.exact 确保只有特定组合键触发Vue.config.keyCodes 定义按键别名合理使用按键修饰符,可以大幅提升应用的交互体验。记住要考虑无障碍访问,为键盘用户提供良好的操作体验。