我正在尝试使用 A-Frame 创建一个 Typescript 类,它允许我渲染模型并在场景中插入元素以响应点击。处理程序应受作为触发器的布尔变量的值的约束;具体来说,只有当此触发器的值设置为 true 时,该类才应插入元素。
我的方法是基于一个组件的注册,我在其中插入了更新函数中处理程序的定义。这是代码的草稿:
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
}
我想了解的是是否可以更新事件侦听器,以便将触发器的新值考虑在内。恐怕当前代码总是插入新的事件侦听器,这应该是我问题的原因。
EDIT:在 Angular 组件模板中,我有一个按钮;当它被按下时,它会将“外部触发器”设置为 true
。我想要做的是找到一种方法让处理程序意识到这一变化。
谢谢大家。
答案 0 :(得分:1)
我认为您应该将 addEventListener 放在 init 中。
现在处于更新,即
<块引用>在组件初始化和组件的任何属性更新时调用(例如,通过 setAttribute)。用于修改实体。 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)
但我不知道它是否会重新运行 init 部分。编辑:这将运行更新 - 而不是初始化。
左上角有一个按钮可以切换球体的可点击性。
如果您不想使用变量,这就是您可以在事件侦听器中访问组件值的方法。
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>
如果这有帮助,请告诉我。