学习Canvas键盘事件处理,掌握按键检测、快捷键实现和键盘控制方法。键盘事件用于处理用户的键盘输入,常用于游戏控制、快捷键和表单输入等场景。
| 事件 | 说明 | 触发时机 |
|---|---|---|
| keydown | 按键按下 | 按键被按下时 |
| keyup | 按键释放 | 按键被释放时 |
| keypress | 字符键按下 | 已废弃,不推荐使用 |
document.addEventListener('keydown', (e) => {
console.log('按键按下:', e.key)
})
document.addEventListener('keyup', (e) => {
console.log('按键释放:', e.key)
})
document.addEventListener('keydown', (e) => {
console.log('按键值:', e.key)
console.log('按键码:', e.code)
console.log('键码(已废弃):', e.keyCode)
console.log('是否重复:', e.repeat)
console.log('Ctrl键:', e.ctrlKey)
console.log('Shift键:', e.shiftKey)
console.log('Alt键:', e.altKey)
console.log('Meta键:', e.metaKey)
})
document.addEventListener('keydown', (e) => {
// key: 按键的字符值
// code: 按键的物理位置
// 例如:按下 'a' 键
// e.key = 'a' (小写) 或 'A' (大写时)
// e.code = 'KeyA' (始终不变)
// 例如:按下左边数字键 '1'
// e.key = '1'
// e.code = 'Digit1'
// 例如:按下右边数字键盘 '1'
// e.key = '1'
// e.code = 'Numpad1'
})
const keyState = {}
document.addEventListener('keydown', (e) => {
keyState[e.code] = true
})
document.addEventListener('keyup', (e) => {
keyState[e.code] = false
})
function isKeyDown(code) {
return keyState[code] === true
}
function gameLoop() {
if (isKeyDown('ArrowUp')) {
player.y -= speed
}
if (isKeyDown('ArrowDown')) {
player.y += speed
}
if (isKeyDown('ArrowLeft')) {
player.x -= speed
}
if (isKeyDown('ArrowRight')) {
player.x += speed
}
requestAnimationFrame(gameLoop)
}
gameLoop()
class KeyboardState {
constructor() {
this.keys = new Map()
this.justPressed = new Set()
this.justReleased = new Set()
this.bindEvents()
}
bindEvents() {
document.addEventListener('keydown', (e) => {
if (!this.keys.get(e.code)) {
this.justPressed.add(e.code)
}
this.keys.set(e.code, true)
})
document.addEventListener('keyup', (e) => {
this.keys.set(e.code, false)
this.justReleased.add(e.code)
})
}
isDown(code) {
return this.keys.get(code) === true
}
isUp(code) {
return !this.isDown(code)
}
wasPressed(code) {
return this.justPressed.has(code)
}
wasReleased(code) {
return this.justReleased.has(code)
}
update() {
this.justPressed.clear()
this.justReleased.clear()
}
}
const keyboard = new KeyboardState()
function gameLoop() {
if (keyboard.wasPressed('Space')) {
player.jump()
}
if (keyboard.isDown('ArrowRight')) {
player.moveRight()
}
keyboard.update()
requestAnimationFrame(gameLoop)
}
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 's') {
e.preventDefault()
console.log('保存')
}
if (e.ctrlKey && e.shiftKey && e.key === 'S') {
e.preventDefault()
console.log('另存为')
}
if (e.ctrlKey && e.key === 'z') {
e.preventDefault()
console.log('撤销')
}
if (e.ctrlKey && e.key === 'y') {
e.preventDefault()
console.log('重做')
}
})
class ShortcutManager {
constructor() {
this.shortcuts = new Map()
this.bindEvents()
}
bindEvents() {
document.addEventListener('keydown', (e) => {
const combo = this.getCombo(e)
const handler = this.shortcuts.get(combo)
if (handler) {
e.preventDefault()
handler(e)
}
})
}
getCombo(e) {
const parts = []
if (e.ctrlKey) parts.push('Ctrl')
if (e.shiftKey) parts.push('Shift')
if (e.altKey) parts.push('Alt')
if (e.metaKey) parts.push('Meta')
parts.push(e.key)
return parts.join('+')
}
register(combo, handler) {
this.shortcuts.set(combo, handler)
return this
}
unregister(combo) {
this.shortcuts.delete(combo)
return this
}
}
const shortcuts = new ShortcutManager()
shortcuts
.register('Ctrl+S', () => save())
.register('Ctrl+Z', () => undo())
.register('Ctrl+Y', () => redo())
.register('Delete', () => deleteSelected())
const player = {
x: 200,
y: 150,
speed: 5
}
const keys = {}
document.addEventListener('keydown', (e) => {
keys[e.code] = true
})
document.addEventListener('keyup', (e) => {
keys[e.code] = false
})
function update() {
if (keys['KeyW'] || keys['ArrowUp']) player.y -= player.speed
if (keys['KeyS'] || keys['ArrowDown']) player.y += player.speed
if (keys['KeyA'] || keys['ArrowLeft']) player.x -= player.speed
if (keys['KeyD'] || keys['ArrowRight']) player.x += player.speed
}
function gameLoop() {
update()
render()
requestAnimationFrame(gameLoop)
}
let inputText = ''
let cursorVisible = true
document.addEventListener('keydown', (e) => {
if (e.key === 'Backspace') {
inputText = inputText.slice(0, -1)
} else if (e.key === 'Enter') {
console.log('提交:', inputText)
inputText = ''
} else if (e.key.length === 1) {
inputText += e.key
}
})
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = '#fff'
ctx.fillRect(50, 100, 300, 30)
ctx.strokeStyle = '#3498db'
ctx.strokeRect(50, 100, 300, 30)
ctx.fillStyle = '#333'
ctx.font = '16px Arial'
ctx.textAlign = 'left'
ctx.fillText(inputText, 55, 120)
if (cursorVisible) {
const textWidth = ctx.measureText(inputText).width
ctx.fillStyle = '#333'
ctx.fillRect(55 + textWidth, 105, 1, 20)
}
requestAnimationFrame(render)
}
setInterval(() => {
cursorVisible = !cursorVisible
}, 500)
render()
const hiddenInput = document.createElement('input')
hiddenInput.style.position = 'absolute'
hiddenInput.style.opacity = '0'
hiddenInput.style.pointerEvents = 'none'
document.body.appendChild(hiddenInput)
canvas.addEventListener('click', () => {
hiddenInput.focus()
})
hiddenInput.addEventListener('input', (e) => {
console.log('输入:', e.target.value)
})
canvas.tabIndex = 0
canvas.addEventListener('focus', () => {
console.log('Canvas获得焦点')
})
canvas.addEventListener('blur', () => {
console.log('Canvas失去焦点')
})
canvas.addEventListener('click', () => {
canvas.focus()
})
canvas.addEventListener('focus', () => {
canvas.style.outline = '2px solid #3498db'
})
canvas.addEventListener('blur', () => {
canvas.style.outline = 'none'
})
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault()
}
if (e.ctrlKey && e.key === 'a') {
e.preventDefault()
}
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
e.preventDefault()
}
})