如何解决在 A-Frame 中动态创建的添加事件侦听器 工作示例
我创建了一个类,可帮助我使用 A-Frame 显示 3D 模型。在这个类中,有一些在运行时创建的球体插入到场景中。我正在尝试添加一个事件侦听器(单击这些球体时我必须显示一条消息)
代码如下:
export class AFrameObjViewNavMarkProvider implements Provider {
// Class Variables...
// Constructor...
// ----- Method ----- \\
public setPointerService(pointeRSService: PointeRSService) {
// method code...
}
public setPointerTrigger(value: boolean) {
// method code...
}
// ----- Handlers ----- \\
// click Handler
clickHandler(event,model: Model){
// code for saving into backend...
// save pointer into the back-end
this.pointeRSService.loadPointer(newPointer).subscribe((pointer) => {
this.showPointer(pointer);
});
}
showPointer(pointer: Pointer){
// create a string containing the position
let pointString = pointer.position[0].toFixed(3) + " "
+ pointer.position[1].toFixed(3) + " "
+ pointer.position[2].toFixed(3);
// compute the Box that contains the model
let modelRef = <any>document.getElementById("model");
const Box = new THREE.Box3().setFromObject(modelRef.object3D);
const BoxSizes = Box.getSize(new THREE.Vector3());
// 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");
let marker = document.createElement("a-sphere");
scene.appendChild(marker);
marker.setAttribute("class","pointer");
marker.setAttribute("radius",`${radius}`);
marker.setAttribute("color","#CC0000");
marker.setAttribute("position",pointString);
}
// ----- Visual Methods ----- \\
renderModel(model: Model) {
// position-setter is used to set the model position according to its size
AFrameUtils.registerPositionSetter();
// reference to the provider itself
let caller: any = this;
function clickHandler(event) {
caller.clickHandler(event,model);
}
// sets the behavIoUr in response to a click event
AFRAME.registerComponent('click-handler',{
// init also calls update
init: function () {
let mouseDownTime: number = null;
let mouseDownPoint: any = null;
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 within 185 ms
// we consider the event as a click
if (timeDiff <= 185 && JSON.stringify(mouseDownPoint) === JSON.stringify(mouseUpPoint)) {
clickHandler(event);
}
});
}
});
let renderingArea = document.getElementById('rendering-area');
renderingArea.innerHTML = `
<a-scene embedded id="scene" cursor="rayOrigin: mouse" raycaster="objects: .clickable">
<!-- Assets deFinition -->
<a-assets>
<a-asset-item id="object-ref" src="${model.sources[0]}"></a-asset-item>
<a-asset-item id="material-ref" src="${model.sources[1]}"></a-asset-item>
</a-assets>
<!-- Using the asset management system. -->
<a-obj-model id="model" class="clickable" src="#object-ref" mtl="#material-ref" position-setter click-handler>
</a-obj-model>
<!-- Camera -->
<a-camera id="camera" wasd-controls="fly:true"></a-camera>
<!-- Environment elements-->
<a-sky id="sky" color="#000000"></a-sky>
</a-scene>
`;
setTimeout(() => {
this.pointeRSService.getPointersByModelId(model.id).subscribe(pointers => {
for(let pointer of pointers){
this.showPointer(pointer);
}
let markers = Array.from(document.getElementsByClassName('pointer'));
for(let marker of markers){
marker.addEventListener('click',() => {
console.log('click on pointer');
})
}
});
},125);
}
}
和截图:
AFRAME.registerComponent('pointer-handler',{
init: function(){
this.el.addEventListener('click',() => {
console.log('click on pointer');
});
}
});
并在 setAttribute("pointer-handler","")
方法中使用 showPointer
第二次尝试:我尝试将使用 marker.addEventListener
的事件侦听器直接添加到 showPointer
方法中。
第三次尝试:第三次尝试可以在代码中找到,进入setTimeout
的回调。
每次尝试都不行;如果我尝试单击一个球体,则什么也不会发生。但是,如果我打开 A-Frame 检查器,导航到其中一个球体并单击它,则会记录该消息。我怀疑添加了处理程序,但某些原因导致无法检测到点击。
我们将不胜感激。
谢谢!
EDIT:您可以找到存储库 here
解决方法
使用 setAttribute("pointer-handler","")
方法绝对有效,是实现您想要实现的目标的正确方法。
我认为可能是 click
事件导致了问题。我建议您将其替换为 mouseup
和 mousedown
事件。
还要确保您确实可以触发事件 - 您需要将光标连接到相机
工作示例
全屏运行(运行片段后右上角查看整个场景 - 关闭也在右上角)。
您可以通过按左上角的按钮来添加新元素。看看有时会触发点击,有时根本不触发。
let boxCounter = 0;
function createNewElement() {
let box = document.createElement("a-box");
boxCounter++;
box.setAttribute("position","" + boxCounter + " 0 -2");
box.setAttribute("scale","0.5");
box.setAttribute("color","red");
box.setAttribute("click-handler","");
document.getElementById("scene").appendChild(box);
}
<!DOCTYPE html>
<html>
<head>
<script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script>
</head>
<body>
<script>
AFRAME.registerComponent('click-handler',{
init: function() {
this.el.addEventListener('mousedown',(event) => {
console.log("I was mousedowned!");
this.el.setAttribute('material','color','green');
});
this.el.addEventListener('mouseup',(event) => {
console.log("I was mouseuped!");
this.el.setAttribute('material','red');
});
this.el.addEventListener('click',(event) => {
console.log("I was clicked!");
this.el.setAttribute('scale','0.5 0.5 0.5');
});
}
});
</script>
<a-scene id="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 color="red" position="0 0 -2" scale="0.5 0.5 0.5" click-handler></a-sphere>
</a-scene>
<button onclick="createNewElement()" style="width: 100px; height: 100px; position: absolute; top: 0; left: 0;" value="toggle"></button>
</body>
</body>
</html>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。