javascript - 两个不同画布上的 document.onkeydown 冲突
问题描述
我正在尝试设置两个不同的画布,其中包含它们自己的实体,可以通过不同的键盘输入移动。每个画布都有自己的脚本文件。但是只有第二个画布似乎是活动的,通过测试我得出的结论是,第二个画布的 document.onkeydown() 函数使我的第一个画布“非活动”(绘图功能很好,但 document.onkeydown 和 onkeyup 不是工作),但我找不到原因。
这是第一个画布的代码:
var canvas;
var player_y = 480/2;
const paddle_height = 100;
const paddle_width = 20;
document.addEventListener('DOMContentLoaded', function () {
canvas = document.getElementById('canvas');
draw();
});
function draw() {
var context = canvas.getContext('2d');
//canvas
context.fillStyle = color[3];
context.fillRect(0, 0, canvas.width, canvas.height);
// Draw middle line
context.strokeStyle = color[1];
context.beginPath();
context.moveTo(canvas.width / 2, 0);
context.lineTo(canvas.width / 2, canvas.height);
context.stroke();
//draw left paddle
context.fillStyle = color[1];
context.beginPath();
context.fillRect(10, player_y-paddle_height/2, paddle_width, paddle_height);
context.fill();
}
var UP = false;
var DOWN = false;
function move() {
if(UP && player_y > paddle_height/2 ) {
player_y -= 5;
}
if(DOWN && player_y < 480 - paddle_height/2) {
player_y += 5;
}
draw();
}
document.onkeydown = function(e) {
if(e.keyCode == 38) UP = true;
if(e.keyCode == 40) DOWN = true;
}
document.onkeyup = function(e) {
if(e.keyCode == 38) UP = false;
if (e.keyCode == 40) DOWN = false;
}
setInterval (update, 10);
function update() {
move();
}
这是第二个画布的代码:
var canvas_exemple;
var cube = {
sz: 50,
x: 400/2,
y: 200/2,
sp: 5
}
document.addEventListener('DOMContentLoaded', function () {
canvas_exemple = document.getElementById('canvas_exemple');
draw_exemple();
});
function draw_exemple() {
var context = canvas_exemple.getContext('2d');
//canvas
context.fillStyle = "#242423";
context.fillRect(0, 0, canvas_exemple.width, canvas_exemple.height);
//draw cube
context.fillStyle = "#c70e0e";
context.beginPath();
context.fillRect(cube.x, cube.y, cube.sz, cube.sz);
context.fill();
}
function move_exemple() {
document.onkeydown = function (e) {
if (e.keyCode == 90 && cube.y > 0) cube.y -= cube.sp;
if (e.keyCode == 83 && cube.y < 200 - cube.sz) cube.y += cube.sp;
if (e.keyCode == 81 && cube.x > 0) cube.x -= cube.sp;
if (e.keyCode == 68 && cube.x < 400 - cube.sz) cube.x += cube.sp;
draw_exemple();
}
}
解决方案
...但我找不到原因
因为你覆盖它:
// First file:
document.onkeydown = function (e) { /*...*/ };
// Second file:
document.onkeydown = function (e) { /*...*/ }; // <=== Overwrites the first
这是对属性的分配。一个属性只能有一个值(尽管 DOM 中有一些奇怪的属性,比如document.cookie
)。
如果你想在document
, 上使用多个 keydown 处理程序addEventListener
,而不是赋值,但你可能不希望这样。如果您将两个事件处理程序keydown
放在同一个文档上,则两者都会被调用。你如何确定哪个应该做某事?
相反,将处理程序放在canvas
元素上,而不是document
. 这确实意味着用户必须聚焦画布才能让键盘事件转到它,但是您有两个画布,因此您需要一些方法让用户指示他们将输入定向到哪个画布。(请注意,为了更容易聚焦canvas
元素,您可能需要将其放在tabindex="0"
上面 [此处详细信息]。)
(如果需要,您仍然可以使用处理程序document
,但要查看事件是否通过相关的canvas
,但在这种情况下,只需将处理程序添加到 就更简单了canvas
。)
我在下面提供了一个示例。在这个例子中,有很多重复的代码,通常我会创建一个可以传递东西的函数,但是我把它分开了,因为代码在你的问题中是分开的,有时重复的代码比参数化的代码更容易阅读. 您可以使用鼠标或选项卡在画布之间切换。活动画布周围有一个绿色边框。
// Canvas 1
const canvas1 = document.getElementById("canvas1");
const ctx1 = canvas1.getContext("2d");
let x1 = Math.floor(canvas1.width / 2);
let y1 = Math.floor(canvas1.height / 2);
draw1();
canvas1.addEventListener("keydown", (event) => {
switch (event.key) {
case "ArrowLeft":
x1 = x1 > 0 ? x1 - 1 : x1;
break;
case "ArrowRight":
x1 = x1 < 300 ? x1 + 1 : x1;
break;
case "ArrowUp":
y1 = y1 > 0 ? y1 - 1 : y1;
break;
case "ArrowDown":
y1 = y1 < 300 ? y1 + 1 : y1;
break;
default:
return;
}
event.preventDefault();
draw1();
});
function draw1() {
ctx1.fillRect(x1, y1, 1, 1);
}
// Canvas 2
const canvas2 = document.getElementById("canvas2");
const ctx2 = canvas2.getContext("2d");
let x2 = Math.floor(canvas2.width / 2);
let y2 = Math.floor(canvas2.height / 2);
ctx2.fillRect(x2, y2, 1, 1);
canvas2.addEventListener("keydown", (event) => {
let originalX = x2;
let originalY = y2;
switch (event.key) {
case "ArrowLeft":
x2 = x2 > 0 ? x2 - 5 : x2;
break;
case "ArrowRight":
x2 = x2 < 300 ? x2 + 5 : x2;
break;
case "ArrowUp":
y2 = y2 > 0 ? y2 - 5 : y2;
break;
case "ArrowDown":
y2 = y2 < 300 ? y2 + 5 : y2;
break;
default:
return;
}
event.preventDefault();
if (x2 !== originalX || y2 !== originalY) {
ctx2.strokeStyle = "blue";
ctx2.beginPath();
ctx2.moveTo(originalX, originalY);
ctx2.lineTo(x2, y2);
ctx2.closePath();
ctx2.stroke();
}
});
// Focus the first canvas by default
canvas1.focus();
html {
box-sizing: border-box;
font-family: sans-serif;
}
*, *:before, *:after {
box-sizing: inherit;
}
canvas {
border: 1px solid grey;
margin: 8px;
}
canvas:focus {
outline: green solid 3px;
}
<div>Canvas 1:</div>
<canvas id="canvas1" tabindex="0" width="200" height="200"></canvas>
<div>Canvas 2:</div>
<canvas id="canvas2" tabindex="0" width="200" height="200"></canvas>
推荐阅读
- macos - 如何在给定布局 ID 的情况下转到正确的文件制作器布局?
- r - 基于 R Shiny 仪表板中的单选按钮进行绘图
- reactjs - 为什么打字稿不显示错误?(反应)
- c++ - C++ Incorrect display of function parameters
- php - 将新行添加到数据库时回显
- three.js - three.js 有没有办法检测剪辑位置或何时基于缩放到达远剪辑?
- android - 颤振应用程序编译错误:位置参数太少:需要 1,给定 0。领先 = 图标按钮(
- google-apps-script - 在 Apps 脚本中获取完整的浏览器 URL
- three.js - 在three.js中实现冒名顶替者
- python - 如何通过 Selenium ActionChain 和 Python 点击元素