避免将按键事件从 dat.GUI 传播到 Three.js 场景

Avoid propagating keydown events from dat.GUI to Three.js scene

我有这段代码(见下文)和 2 个事件侦听器:

renderer.domElement.addEventListener("pointerdown", changeColor, false);
document.addEventListener("keydown", changeColor, false);

它们都会触发立方体的颜色变化。但是,当我在 GUI 中编辑输入参数时,keydown 事件也会导致颜色发生变化,我想避免这种情况。

我猜这是因为我在 keydown 事件中使用 document.addEventListener。但是,如果我改用 renderer.domElement.addEventListener,它将不起作用。

编辑 GUI 参数时如何避免 keydown 事件传播?

代码

var renderer, controls, scene, camera;
var cube;

init();

function init() {

    // Scene
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xb0b0b0);

    // Camera
    camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(300, 300, 300);
    camera.up.set(0, 0, 1);

    // Light
    var ambientLight = new THREE.AmbientLight(0xcccccc, 0.2);
    scene.add(ambientLight);

    // Helpers
    var helpers = new THREE.Group();
    var grid = new THREE.GridHelper(200, 10);
    grid.rotation.x = Math.PI / 2;
    var axis = THREE.AxisHelper(100);
    helpers.add(grid);
    helpers.add(axis);
    scene.add(helpers);

    // Renderer
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // Controls
    controls = new THREE.OrbitControls(camera, renderer.domElement);

    // Event listeners
    controls.addEventListener("change", render, false);

    // Draw the cube
    var cubeGeometry = new THREE.BoxGeometry( 50, 50, 50 );
        var cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x000088 } );
        cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
    scene.add(cube);
    
    // GUI
    params = {
        size: 50,
    };
    var gui = new dat.GUI();
    gui.add(params, "size", 0.0, 100, 1);
    
    // Listeners
    renderer.domElement.addEventListener("pointerdown", changeColor, false);
    document.addEventListener("keydown", changeColor, false);

    // Render
    render();
}

function changeColor(event) {
    cube.material.color.set(Math.random() * 0xffffff);
    cube.material.needsUpdate = true;
    render();
}

function render() {
    renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<html>
    <head>
        <script src="https://unpkg.com/three@0.126.0/build/three.min.js"></script>
        <script src="https://unpkg.com/three@0.126.0/examples/js/controls/OrbitControls.js"></script>
        <script src="https://stemkoski.github.io/Three.js/js/DAT.GUI.min.js"></script>
    </head>
    <body>
    </body>
</html>

不确定这是最好的方法,但您可以通过检查事件处理程序的目标来忽略来自事件处理程序的按键事件。如果目标是 input,则什么都不做:

function changeColor(event) {
    // Ignore key event when editing dat.GUI input values
    if (event.target.localName == "input") {
        return;
    }
    // [...]
}