typescript - 根据布尔变量更新 A-Frame 中的事件侦听器
问题描述
我正在尝试使用 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
}
我想了解的是是否可以更新事件侦听器,以便它考虑到触发器的新值。恐怕当前代码总是插入新的事件侦听器,这应该是我的问题的原因。
编辑:在 Angular 组件模板中,我有一个按钮;当它被按下时,它将“外部触发器”设置为true
. 我正在尝试做的是找到一种方法让处理程序意识到这种变化。
谢谢你们。
解决方案
我认为您应该将 addEventListener 放在init中。
现在它正在更新中
在组件初始化和组件的任何属性更新(例如,通过 setAttribute)时调用。用于修改实体。来源
因此,每次发生变化时,您最终都会添加一个事件侦听器。
然后您可能应该在事件侦听器内部检查您的标志是否已设置。在事件侦听器中,您应该能够通过以下方式访问变量:
event.target.components['component-name'].data.trigger
对于属性本身。
event.target.components['component-name'].data
如果您不指定架构属性的名称,这将起作用,而只使用称为单属性组件的东西
event.target.components['component-name'].variable
对于组件内的变量或 this.variable
同样在组件内部,您可以自由更改触发器变量 - 但不是与架构相关的变量,而是您将在 initlet trigger = this.data.trigger;
中为您需要使用的架构创建的变量,el.setAttribute('click-handler', true)
但我不知道它是否会重新运行 init部分与否。编辑:这将运行更新 - 而不是 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>
让我知道这是否有帮助。
推荐阅读
- android - 如何在 Recycler 视图中使用 exoPlayer(多个视频)?如何从列表或数组中读取视频标题、网址?
- javascript - 我的 React JS 网站没有显示 iPhone/iPad 上的所有图像
- ios - 嵌入导航栏中的 UISearchController 的表格视图和搜索栏的奇怪动画
- python - Micropython没有找到任何模块属性
- excel - Excel - 在 texboxes 中搜索文本
- perforce - 如何使用 p4 命令行配置 Perforce 连接参数?
- windows - 使用批处理脚本导入 sql 文件
- csv - 不以表格方式从 csv 文件插入数据
- javascript - 不同父组件之间共享子组件不渲染?
- vba - 使用 WScript.Shell 将输出重定向到新文件 vba