根据布尔变量更新 A-Frame 中的事件监听器

Update Event Listener in A-Frame according to a boolean variable

我正在尝试使用 A-Frame 创建一个 Typescript class,它允许我渲染模型并在场景中插入元素以响应点击。处理程序应受充当触发器的布尔变量值的约束;具体来说,只有当此触发器的值设置为 true 时,class 才应插入一个元素。

我的方法是基于一个组件的注册,在其中我在更新函数中插入处理程序的定义。这是代码草稿:

AFRAME.registerComponent('click-handler', {
  schema: {
    trigger: { type: 'boolean' },
  },

  // init function definition

  update: function () {
    let mouseDownTime: number = null;
    let mouseDownPoint: any = null;
    let trigger = this.data.trigger;

    function clickHandler(event) {
      let point = event.detail.intersection.point;
      let pointString = point.x.toFixed(3) + " " + point.y.toFixed(3) + " " + point.z.toFixed(3);

      // compute the box that contains the model
      let model = <any>document.getElementById("model")
      const box = new THREE.Box3().setFromObject(model.object3D);
      const boxSizes = box.getSize(new THREE.Vector3());

      if (trigger) {
        // compute the min size of the box (x, y, z)
        // it will be used to set pointer radius
        let minBoxSize = Math.min(boxSizes.x, boxSizes.y, boxSizes.z);
        let radius = minBoxSize / 30;

        let scene = document.getElementById("scene");
        var marker = document.createElement("a-sphere");
        scene.appendChild(marker);

        marker.setAttribute("class", "pointer");
        marker.setAttribute("radius", `${radius}`);
        marker.setAttribute("color", "#CC0000");
        marker.setAttribute("position", pointString);
      }
    }

    this.el.addEventListener('mousedown', event => {
      mouseDownTime = new Date().getTime();
      mouseDownPoint = event.detail.intersection.point;
    });

    this.el.addEventListener('mouseup', event => {
      if (!event.detail.intersection) return;

      let mouseUpTime = new Date().getTime();
      let mouseUpPoint = event.detail.intersection.point;

      // compute the differences (time and position) between press and release
      let timeDiff = mouseUpTime - mouseDownTime;

      // if press and release occur on the same point within 185 ms
      //  we consider the overall "event" as a click
      if (timeDiff <= 185 && JSON.stringify(mouseDownPoint) === JSON.stringify(mouseUpPoint)) {
        clickHandler(event);
      }
    });
  },

  // remove function definition
}

我想了解的是,是否可以更新事件侦听器,以便它考虑触发器的新值。恐怕当前代码总是插入新的事件侦听器,这应该是我的问题的原因。

编辑:在Angular组件模板中我有一个按钮;当它被按下时,它会将“外部触发器”设置为 true。我想做的是找到一种方法让处理程序知道此更改。

谢谢大家

我认为你应该将 addEventListener 放在 init.

目前在更新中,即

Called both when the component is initialized and whenever any of the component’s properties is updated (e.g, via setAttribute). Used to modify the entity. source

所以你最终会在每次发生变化时添加一个事件监听器。

然后您可能应该在事件侦听器内部检查您的标志是否已设置。在事件侦听器中,您应该能够通过以下方式访问变量:

event.target.components['component-name'].data.trigger 属性本身。

event.target.components['component-name'].data 如果您不指定模式的名称 属性,并且只使用名为 single property component

的名称,这将起作用

event.target.components['component-name'].variable 对于组件内部的变量或 this.variable

同样在组件内部,您可以自由更改 trigger 变量 - 但不是与架构相关的变量,而是您将在 init let trigger = this.data.trigger; 中创建的变量您需要使用 el.setAttribute('click-handler', true) 的架构,但我不知道它是否会重新 运行 初始化部分。编辑:这将 运行 更新 - 而不是初始化。

工作示例:

左上角有一个按钮可以切换球体的可点击性。

如果您不想使用变量,这就是您可以在事件侦听器中访问组件值的方法。 event.target.components['click-handler'].trigger

function toggleClickHandler() {
  let el = document.getElementById("clickableElement");
  // here you can set the new value for the component
  // also look how you can access component variable from outside
  // changing the value will trigger the 'update' lifecycle function 
  el.setAttribute("click-handler", "trigger", !el.components['click-handler'].trigger);
  console.log(el.components['click-handler'].trigger);
}
<!DOCTYPE html>
<html>
  <head>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
  </head>
  <body>
    <!-- script here because on stack JS is after the HTML --> 
    <script>
      AFRAME.registerComponent('click-handler', {
        schema: {
          // if you specify name you have to use it when setting the attribute
          trigger: { type: 'boolean' },
        },
        // init function definition
        init: function() {
          this.el.addEventListener('mousedown', (event) => {
            if (!this.trigger) return;
            // ... your logic ...
            console.log("I was mousedowned!");
            this.el.setAttribute('material', 'color', 'green');
          });

          this.el.addEventListener('mouseup', (event) => {
            if (!this.trigger) return;
            // ... your logic ...
            console.log("I was mouseuped!");
            this.el.setAttribute('material', 'color', 'red');
          });
        },
        // update is called once on init and every time the elements attribute is changed.
        update: function() {
          this.trigger = this.data.trigger;
        }
      });
    </script>
    <a-scene>
      <a-entity camera look-controls>
        <a-entity cursor="fuse: true; fuseTimeout: 500;"
                  position="0 0 -1"
                  geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
                  material="color: black; shader: flat">
        </a-entity>
      </a-entity>
      <a-sphere id="clickableElement" scale="1 2 3" position="6 1 -5" click-handler="trigger: true">
      </a-sphere>
    </a-scene>
    <button onclick="toggleClickHandler()" style="width: 100px; height: 100px; position: absolute; top: 0; left: 0;" value="toggle"></button>
  </body>
</html>

如果有帮助请告诉我。