对于canvas
元素,它支持javascript所有鼠标事件,但是如果监听键盘事件则并不会生效。
// 有效
canvas.addEventListener('click', (e) => {
console.log('触发点击了')
})
// 无效
canvas.addEventListener('keydown', (e) => {
console.log('触发按键了')
})
其原因在于,键盘输入事件只发生在当前拥有焦点的HTML元素上,如果没有元素拥有焦点,那么事件将会上移至windows和document对象,所以有两种常用方法来解决这个问题:
-
如果canvas元素和windows长宽基本一致,可以通过在windows对象上绑定键盘事件来代替对canvas元素的监听与处理。
window.addEventListener('keydown', doKeyDown, true)
-
让canvas元素处于聚焦状态,并给它绑定键盘事件。
<canvas tabindex="0"></canvas>
将
tabindex
设置为0或更大。
下面通过示例详细的介绍第二种方法:
<!-- html部分 -->
<canvas id="canvas" tabindex="0"></canvas>
// js部分
const canvas = document.getElementById('canvas')
canvas.focus()
canvas.addEventListener('keydown', (e) => {
console.log(`keyCode: ${e.keyCode}`)
})
这样就可以让canvas在一开始处于聚焦状态,并相应键盘输入事件。
不过tabindex
聚焦的元素会有一层默认的外框,标识该元素处于聚焦状态。如果不想要显示外框,可以通过css样式去除:
canvas:focus {
outline:none;
}
可以写一个实际应用来测试,比如用键盘的上下左右或者wsad键操作一个小方块,在canvas画布中移动。
<!-- html部分 -->
<canvas id="canvas" tabindex="0"></canvas>
<!-- css部分 -->
<style>
#canvas{
width: 100vw;
height: 100vh;
background-color: #4ab7bd;
}
#canvas:focus{
outline: none;
}
</style>
<!-- js部分 -->
<script>
window.onload = function() {
// 画布的长宽
const canvas = document.getElementById('canvas')
const canvasWidth = canvas.clientWidth
const canvasHeight = canvas.clientHeight
// 在画布上移动的方块的长宽
const [rectWidth, rectHeight] = [40, 40]
// 方块的横纵坐标
let [rectX, rectY] = [0, 0]
// 初始化
canvas.width = canvasWidth
canvas.height = canvasHeight
let context = canvas.getContext('2d')
// 给方块设置颜色和初始坐标(中心点),绘制
context.fillStyle = 'red'
rectX = (canvasWidth - rectWidth) / 2
rectY = (canvasHeight - rectHeight) / 2
context.fillRect(rectX, rectY, rectWidth, rectHeight)
// canvas元素上监听键盘输入事件
canvas.addEventListener('keydown', doKeyDown, true)
canvas.focus() // 让canvas聚焦
function clearCanvas() {
context.clearRect(0, 0, canvasWidth, canvasHeight)
}
function doKeyDown(e) {
// 获取keyCode
const keyCode = e.keyCode ? e.keyCode : e.which
// 向上箭头 / w,让纵坐标向上移动10
if (keyCode === 38 || keyCode === 87) {
clearCanvas()
rectY -= 10
if (rectY < 0) {
rectY = 0
}
context.fillRect(rectX, rectY, rectWidth, rectHeight)
}
// 向下箭头 / s,让纵坐标向下移动10
if (keyCode === 40 || keyCode === 83) {
clearCanvas()
rectY += 10
if (rectY > canvasHeight - rectHeight) {
rectY = canvasHeight - rectHeight
}
context.fillRect(rectX, rectY, rectWidth, rectHeight)
}
// 向左箭头 / a,让纵坐标向左移动10
if (keyCode === 37 || keyCode === 65) {
clearCanvas()
rectX -= 10
if (rectX < 0) {
rectX = 0
}
context.fillRect(rectX, rectY, rectWidth, rectHeight)
}
// 向右箭头 / d,让纵坐标向右移动10
if (keyCode === 39 || keyCode === 68) {
clearCanvas()
rectX += 10
if (rectX > canvasWidth - rectWidth) {
rectX = canvasWidth - rectWidth
}
context.fillRect(rectX, rectY, rectWidth, rectHeight)
}
}
}
</script>
当canvas元素处于聚焦状态时,可以监听到键盘事件,当其失去焦点时,则也会失去键盘监听。
我们可以基于此进行canvas小游戏开发,比如贪吃蛇、推箱子、走迷宫、射击、俄罗斯方块等等。