For the Canvas element, it supports all mouse events in javascript, but does not work if you listen for keyboard events.

/ / effective
canvas.addEventListener('click'.(e) = > {
  console.log('Triggered click')})/ / is invalid
canvas.addEventListener('keydown'.(e) = > {
  console.log('Button triggered')})Copy the code

The reason for this is that keyboard input events only occur on HTML elements that currently have focus. If no element has focus, the event will be moved up to Windows and Document objects, so there are two common ways to solve this problem:

  1. If canvas element is basically the same length and width as Windows, keyboard events can be bound to Windows objects to replace the monitoring and processing of Canvas element.

    window.addEventListener('keydown', doKeyDown, true)
    Copy the code
  2. Leave the Canvas element in focus and bind keyboard events to it.

    <canvas tabindex="0"></canvas>
    Copy the code

    Set tabIndex to 0 or greater.

The following is a detailed example of the second method:

<! -- HTML section -->
<canvas id="canvas" tabindex="0"></canvas>
Copy the code
/ / js parts
const canvas = document.getElementById('canvas')
canvas.focus()
canvas.addEventListener('keydown'.(e) = > {
  console.log(`keyCode: ${e.keyCode}`)})Copy the code

This allows the canvas to be in focus at the beginning and keyboard input events accordingly.

However, tabIndex focused elements will have a default outer box that indicates that the element is in focus. If you do not want to display the outer box, you can use CSS styles to remove it:

canvas:focus {
  outline:none;
}
Copy the code

You can write a practical application to test this, such as using the keyboard keys up, down, left, or WSAD to manipulate a small square and move it around the Canvas.

<! -- HTML section -->
<canvas id="canvas" tabindex="0"></canvas>

<! -- CSS section -->
<style>
  #canvas{
    width: 100vw;
    height: 100vh;
    background-color: #4ab7bd;
  }
  #canvas:focus{
    outline: none;
  }
</style>

<! -- js part -->
<script>
window.onload = function() {
  // The width of the canvas
  const canvas = document.getElementById('canvas')
  const canvasWidth = canvas.clientWidth
  const canvasHeight = canvas.clientHeight
  // The length and width of the squares moving on the canvas
  const [rectWidth, rectHeight] = [40.40]
  // The horizontal and vertical coordinates of the box
  let [rectX, rectY] = [0.0]
  / / initialization
  canvas.width = canvasWidth
  canvas.height = canvasHeight
  let context = canvas.getContext('2d')
  // Set the color and initial coordinates (center point) of the block, draw
  context.fillStyle = 'red'
  rectX = (canvasWidth - rectWidth) / 2
  rectY = (canvasHeight - rectHeight) / 2
  context.fillRect(rectX, rectY, rectWidth, rectHeight)

  // The canvas element listens for keyboard input events
  canvas.addEventListener('keydown', doKeyDown, true)
  canvas.focus() // Let canvas focus

  function clearCanvas() {
    context.clearRect(0.0, canvasWidth, canvasHeight)
  }

  function doKeyDown(e) {
    / / get the keyCode
    const keyCode = e.keyCode ? e.keyCode : e.which

    // Up arrow/w, move the ordinate up 10
    if (keyCode === 38 || keyCode === 87) {
      clearCanvas()
      rectY -= 10
      if (rectY < 0) {
        rectY = 0
      }
      context.fillRect(rectX, rectY, rectWidth, rectHeight)
    }

    // Down arrow/s, move the ordinate down 10
    if (keyCode === 40 || keyCode === 83) {
      clearCanvas()
      rectY += 10
      if (rectY > canvasHeight - rectHeight) {
        rectY = canvasHeight - rectHeight
      }
      context.fillRect(rectX, rectY, rectWidth, rectHeight)
    }

    // Arrow to the left/a, move the ordinate to the left by 10
    if (keyCode === 37 || keyCode === 65) {
      clearCanvas()
      rectX -= 10
      if (rectX < 0) {
        rectX = 0
      }
      context.fillRect(rectX, rectY, rectWidth, rectHeight)
    }

    // Go to the right arrow/d and move the ordinate 10 to the right
    if (keyCode === 39 || keyCode === 68) {
      clearCanvas()
      rectX += 10
      if (rectX > canvasWidth - rectWidth) {
        rectX = canvasWidth - rectWidth
      }
      context.fillRect(rectX, rectY, rectWidth, rectHeight)
    }
  }		  
}
</script>
Copy the code

When the Canvas element is in focus state, it can listen to keyboard events; when it loses focus, it will also lose keyboard listening.

We can develop canvas mini-games based on this, such as Snake, box pushing, maze running, shooting, Tetris, etc.