繁体   English   中英

有没有一种方法可以使元素在mousedown事件激活之前消失?

[英]Is there a way to make an element disappear BEFORE the mousedown event activates?

在以下代码段中,您会注意到一个覆盖层要求您“单击任意位置”,并且会在mousedownmouseup事件发生时向画布添加圆圈。 尽管覆盖文本在mousedown时消失,但是如果您在overlay元素上单击任何位置,画布都不会发生mousedown事件来绘制起始圆。

 var canvas = document.getElementById('target'), context = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.addEventListener('mousedown', addStartNode); canvas.addEventListener('mouseup', addEndNode); document.body.addEventListener('mousedown', hideOverlay); document.body.addEventListener('mouseup', showOverlay); function hideOverlay() { document.getElementById('overlay').style.display = 'none'; } function showOverlay() { document.getElementById('overlay').style.display = 'block'; } function addStartNode(evt) { drawCircle(evt.clientX, evt.clientY, 10, 'green'); } function addEndNode(evt) { drawCircle(evt.clientX, evt.clientY, 10, 'blue'); } function drawCircle(x, y, r, c) { context.beginPath(); context.arc(x, y, r, 0, 2 * Math.PI, false); context.fillStyle = c; context.fill(); context.lineWidth = 5; context.strokeStyle = '#003300'; context.stroke(); } 
 html, body { margin: 0; padding: 0; width: 100%; height: 100%; } #overlay { position: absolute; top: 10%; left: 1em; right: 1em; font-size: 4em; text-align: center; z-index: 10; background: rgba(255, 255, 255, 0.7); } #target { position: relative; width: 100%; height: 100%; background: aqua; } .node { position: absolute; background: blue; width: 20px; height: 20px; transform: translate(-50%, -50%); } 
 <div id="overlay"> Click Anywhere </div> <canvas id="target"></canvas> 

我想到了将事件处理程序移动到容器元素或body元素上,以在事件传播时捕获事件的方法,但是有时这是不可能的,例如当您使用HTML5游戏引擎来处理交互时。

有人对此有任何明智的解决方案吗?

编辑:

我真正想到的是将鼠标位置转换为画布的情况要复杂得多,例如在使用游戏引擎或其他画布库时。 在以下代码段中,我使用PIXI.js。 请注意如何拖动左上和中下节点,而不是文本覆盖的右上节点。

 document.body.addEventListener('mousedown', hideOverlay); document.body.addEventListener('mouseup', showOverlay); function hideOverlay() { document.getElementById('overlay').style.display = 'none'; } function showOverlay() { document.getElementById('overlay').style.display = 'block'; } var nodeRadius = 50; function Node(x, y) { this.g = new PIXI.Graphics(); this.position.x = x; this.position.y = y; this.g.node = this; this.drawCircle(); this.g.pivot = new PIXI.Point(nodeRadius / 2, nodeRadius / 2); this.g.interactive = true; this.defaultPos = new PIXI.Point(this.position.x, this.position.y); this.g.on('mousedown', selectNode); this.g.on('mouseup', connectNode); this.g.on('mousemove', moveNode); } Node.prototype = { reset: function() { this.position.x = this.defaultPos.x; this.position.y = this.defaultPos.y; }, drawCircle: function() { this.g.clear(); this.g.beginFill(0x3333FF, 1); this.g.drawCircle(0, 0, nodeRadius); this.g.endFill(); }, connectTo: function(node) { this.drawCircle(); this.g.moveTo(0, 0); this.g.lineStyle(5, 0xDDEEFF); this.g.lineTo(node.position.x - this.position.x, node.position.y - this.position.y); }, get position() { return this.g.position; }, set position(p) { this.g.position = p; } }; var renderer = PIXI.autoDetectRenderer(600, 400), container = new PIXI.Container(), selectedNode = null; container.position.x = -150; container.position.y = 200; container.scale.x = 0.3; container.scale.y = 0.3; var nodes = [ new Node(700, -500), new Node(2200, 50), new Node(1500, 450) ]; for (var i = 0; i < nodes.length; i++) { container.addChild(nodes[i].g); } document.getElementById('content').appendChild(renderer.view); requestAnimationFrame(animate); function animate() { renderer.render(container); requestAnimationFrame(animate); } function selectNode() { this.node.drawCircle(); selectedNode = this.node; } function connectNode() { if (selectedNode) { selectedNode.reset(); selectedNode = null; } } function moveNode() { if (selectedNode) { var mousePos = renderer.plugins.interaction.mouse.getLocalPosition(container); selectedNode.position.x = mousePos.x; selectedNode.position.y = mousePos.y; checkCollision(); } } function checkCollision() { if (selectedNode) { for (var i = 0; i < nodes.length; i++) { if (nodes[i] !== selectedNode && dist(selectedNode.position, nodes[i].position) < nodeRadius * 2) { selectedNode.reset(); selectedNode.connectTo(nodes[i]); selectedNode = null; break; } } } } function dist(p1, p2) { return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); } 
 html, body { margin: 0; padding: 0; width: 100%; height: 100%; } #overlay { position: absolute; top: 100px; left: 10px; width: 580px; font-size: 4em; text-align: center; z-index: 100; background: rgba(255, 255, 255, 0.5); } #content { display: inline-block; position: relative; margin: 1em; } 
 <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css"> <!--<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.min.js"></script>--> <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.js"></script> </head> <body> <div id="content"> <div id="overlay"> Drag one node to another </div> <script src="script.js"></script> </div> </body> </html> 

我故意移动并缩放了container ,因为在游戏中经常发生这种情况。 画布本身可能会偏离页面,甚至可能不会与覆盖图共享同一父对象,这会使将鼠标位置转换为游戏坐标变得更加复杂。

这就是为什么我一直认为最好在mousedown事件触发之前删除overlay元素,因为这样我们就不必担心它了。

这是一个小提琴

将事件侦听器也添加到叠加层中,应该可以解决您的问题:

document.getElementById("overlay").addEventListener('mousedown', addStartNode);

 var canvas = document.getElementById('target'), context = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.addEventListener('mousedown', addStartNode); canvas.addEventListener('mouseup', addEndNode); document.getElementById("overlay").addEventListener('mousedown', addStartNode); document.body.addEventListener('mousedown', hideOverlay); document.body.addEventListener('mouseup', showOverlay); function hideOverlay() { document.getElementById('overlay').style.display = 'none'; } function showOverlay() { document.getElementById('overlay').style.display = 'block'; } function addStartNode(evt) { drawCircle(evt.clientX, evt.clientY, 10, 'green'); } function addEndNode(evt) { drawCircle(evt.clientX, evt.clientY, 10, 'blue'); } function drawCircle(x, y, r, c) { context.beginPath(); context.arc(x, y, r, 0, 2 * Math.PI, false); context.fillStyle = c; context.fill(); context.lineWidth = 5; context.strokeStyle = '#003300'; context.stroke(); } 
 html, body { margin: 0; padding: 0; width: 100%; height: 100%; } #overlay { position: absolute; top: 10%; left: 1em; right: 1em; font-size: 4em; text-align: center; z-index: 10; background: rgba(255, 255, 255, 0.7); } #target { position: relative; width: 100%; height: 100%; background: aqua; } .node { position: absolute; background: blue; width: 20px; height: 20px; transform: translate(-50%, -50%); } 
 <div id="overlay"> Click Anywhere </div> <canvas id="target"></canvas> 

事件在dom的层次结构中冒出。 由于您的“ hideOverlay”是身体上最重要的事件,因此它不会冒泡到画布上。 它必须冒泡,而事实并非如此。 由于叠加层的位置是绝对的,因此它不在画布内,因此单击它不会冒泡到画布上。

简而言之,简单的解决方案是在鼠标按下时仅具有一个事件处理程序,例如body.mousedown,这意味着无论屏幕上发生什么事件,您都希望执行相同的操作,即隐藏叠加层并在其上绘制圆圈画布,因此不要通过两个事件处理程序来使事情复杂化。 在body.mousedown中,隐藏叠加层并绘制一个圆。

顺便说一句,如果您只是从hideOverlay调用addStartNode,您的代码也将按预期工作,但是为什么呢?

您可以简单地为每个鼠标事件使用唯一的事件检测。

因此,首先删除canvas.addEventListener() ,然后收集显示/隐藏覆盖并绘制蓝色/绿色圆圈,如下所示:

var canvas = document.getElementById('target'),
  context = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

document.body.addEventListener('mousedown', mouseDown);
document.body.addEventListener('mouseup', mouseUp);

function mouseDown(evt) {
  document.getElementById('overlay').style.display = 'none';
  drawCircle(evt.clientX, evt.clientY, 10, 'green');
}

function mouseUp(evt) {
  drawCircle(evt.clientX, evt.clientY, 10, 'blue');
  document.getElementById('overlay').style.display = 'block';
}

function drawCircle(x, y, r, c) {
  context.beginPath();
  context.arc(x, y, r, 0, 2 * Math.PI, false);
  context.fillStyle = c;
  context.fill();
  context.lineWidth = 5;
  context.strokeStyle = '#003300';
  context.stroke();
}

nus关于使用dispatchEvent 评论可以解决问题。

document.getElementById('overlay').addEventListener('mousedown', function(evt) {
  setTimeout(function() {
    renderer.view.dispatchEvent(evt);
  },0);
});

 document.body.addEventListener('mousedown', hideOverlay); document.body.addEventListener('mouseup', showOverlay); function hideOverlay() { document.getElementById('overlay').style.display = 'none'; } function showOverlay() { document.getElementById('overlay').style.display = 'block'; } var nodeRadius = 50; function Node(x, y) { this.g = new PIXI.Graphics(); this.position.x = x; this.position.y = y; this.g.node = this; this.drawCircle(); this.g.pivot = new PIXI.Point(nodeRadius / 2, nodeRadius / 2); this.g.interactive = true; this.defaultPos = new PIXI.Point(this.position.x, this.position.y); this.g.on('mousedown', selectNode); this.g.on('mouseup', connectNode); this.g.on('mousemove', moveNode); } Node.prototype = { reset: function() { this.position.x = this.defaultPos.x; this.position.y = this.defaultPos.y; }, drawCircle: function() { this.g.clear(); this.g.beginFill(0x3333FF, 1); this.g.drawCircle(0, 0, nodeRadius); this.g.endFill(); }, connectTo: function(node) { this.drawCircle(); this.g.moveTo(0, 0); this.g.lineStyle(5, 0xDDEEFF); this.g.lineTo(node.position.x - this.position.x, node.position.y - this.position.y); }, get position() { return this.g.position; }, set position(p) { this.g.position = p; } }; var renderer = PIXI.autoDetectRenderer(600, 400), container = new PIXI.Container(), selectedNode = null; document.getElementById('overlay').addEventListener('mousedown', function(evt) { setTimeout(function() { renderer.view.dispatchEvent(evt); }, 0); }); container.position.x = -150; container.position.y = 200; container.scale.x = 0.3; container.scale.y = 0.3; var nodes = [ new Node(700, -500), new Node(2200, 50), new Node(1500, 450) ]; for (var i = 0; i < nodes.length; i++) { container.addChild(nodes[i].g); } document.getElementById('content').appendChild(renderer.view); requestAnimationFrame(animate); function animate() { renderer.render(container); requestAnimationFrame(animate); } function selectNode() { this.node.drawCircle(); selectedNode = this.node; } function connectNode() { if (selectedNode) { selectedNode.reset(); selectedNode = null; } } function moveNode() { if (selectedNode) { var mousePos = renderer.plugins.interaction.mouse.getLocalPosition(container); selectedNode.position.x = mousePos.x; selectedNode.position.y = mousePos.y; checkCollision(); } } function checkCollision() { if (selectedNode) { for (var i = 0; i < nodes.length; i++) { if (nodes[i] !== selectedNode && dist(selectedNode.position, nodes[i].position) < nodeRadius * 2) { selectedNode.reset(); selectedNode.connectTo(nodes[i]); selectedNode = null; break; } } } } function dist(p1, p2) { return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); } 
 html, body { margin: 0; padding: 0; width: 100%; height: 100%; } #overlay { position: absolute; top: 100px; left: 10px; width: 580px; font-size: 4em; text-align: center; z-index: 100; background: rgba(255, 255, 255, 0.5); } #content { display: inline-block; position: relative; margin: 1em; } 
 <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css"> <!--<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.min.js"></script>--> <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.js"></script> </head> <body> <div id="content"> <div id="overlay"> Drag one node to another </div> <script src="script.js"></script> </div> </body> </html> 

请注意,这需要在超时中完成,否则会收到InvalidStateError因为“事件已被调度”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM