document.onkeydown 两个不同 canvas 上的冲突
document.onkeydown conflicts on two different canvas
我正在尝试设置两个不同的 canvas 包含它们自己的实体,可通过不同的键盘输入移动。每个 canvas 都有自己的脚本文件。
然而,只有第二个 canvas 似乎处于活动状态,通过测试我得出的结论是第二个 canvas 的 document.onkeydown() 函数使我的第一个 canvas “非活动"(绘图功能很好,但 document.onkeydown 和 onkeyup 不工作),但我找不到原因。
这是第一个 canvas 的代码:
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();
}
这是第二个代码 canvas:
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();
}
}
...but I cannot find why
因为你覆盖了它:
// First file:
document.onkeydown = function (e) { /*...*/ };
// Second file:
document.onkeydown = function (e) { /*...*/ }; // <=== Overwrites the first
这是对 属性 的分配。 属性 只能有一个值(尽管 DOM 中有一些奇怪的属性,例如 document.cookie
)。
如果你想在 document
上有多个按键处理程序,请使用 addEventListener
,而不是赋值,但你可能不希望那样。如果将 keydown
的两个事件处理程序放在同一个文档中,both 将被调用。你如何确定哪些应该做某事?
相反,将处理程序放在 canvas
元素上,而不是 document
。这确实意味着用户必须关注 canvas 才能让键盘事件转到它,但是你有两个 canvases,所以你需要一些方法让用户指示是哪一个他们正在指导输入。 (请注意,为了更容易聚焦 canvas
元素,您可能需要将 tabindex="0"
放在 [details here] 上。)
(如果需要,您仍然可以在 document
上使用处理程序,但要查看事件是否经过相关的 canvas
,但在这种情况下,仅添加处理程序会更简单canvas
.)
我在下面包含了一个示例。在这个例子中,有很多重复的代码,通常我会做一个函数,我可以把东西传递进去,但我把它分开了,因为代码在你的问题中是分开的,有时重复的代码比参数化代码更容易阅读.您可以使用鼠标或 Tab 在 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>
我正在尝试设置两个不同的 canvas 包含它们自己的实体,可通过不同的键盘输入移动。每个 canvas 都有自己的脚本文件。 然而,只有第二个 canvas 似乎处于活动状态,通过测试我得出的结论是第二个 canvas 的 document.onkeydown() 函数使我的第一个 canvas “非活动"(绘图功能很好,但 document.onkeydown 和 onkeyup 不工作),但我找不到原因。
这是第一个 canvas 的代码:
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();
}
这是第二个代码 canvas:
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();
}
}
...but I cannot find why
因为你覆盖了它:
// First file:
document.onkeydown = function (e) { /*...*/ };
// Second file:
document.onkeydown = function (e) { /*...*/ }; // <=== Overwrites the first
这是对 属性 的分配。 属性 只能有一个值(尽管 DOM 中有一些奇怪的属性,例如 document.cookie
)。
如果你想在 document
上有多个按键处理程序,请使用 addEventListener
,而不是赋值,但你可能不希望那样。如果将 keydown
的两个事件处理程序放在同一个文档中,both 将被调用。你如何确定哪些应该做某事?
相反,将处理程序放在 canvas
元素上,而不是 document
。这确实意味着用户必须关注 canvas 才能让键盘事件转到它,但是你有两个 canvases,所以你需要一些方法让用户指示是哪一个他们正在指导输入。 (请注意,为了更容易聚焦 canvas
元素,您可能需要将 tabindex="0"
放在 [details here] 上。)
(如果需要,您仍然可以在 document
上使用处理程序,但要查看事件是否经过相关的 canvas
,但在这种情况下,仅添加处理程序会更简单canvas
.)
我在下面包含了一个示例。在这个例子中,有很多重复的代码,通常我会做一个函数,我可以把东西传递进去,但我把它分开了,因为代码在你的问题中是分开的,有时重复的代码比参数化代码更容易阅读.您可以使用鼠标或 Tab 在 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>