A-Frame场景中如何实现实体仅单次显示?点击不重复生成#treeModel
解决A-Frame点击屏幕重复生成模型的问题(仅保留一个实例)
要实现无论点击多少次屏幕都只弹出一个#treeModel实体,核心是阻止重复执行模型创建逻辑。以下是两种可行的解决方案:
方案一:添加实例跟踪状态变量
在组件初始化时声明一个状态变量,标记树模型是否已生成。每次点击屏幕时先检查该变量,仅当未生成时才执行创建逻辑。
修改后的完整代码:
init() { this.raycaster = new THREE.Raycaster() this.camera = document.getElementById('camera') this.threeCamera = this.camera.getObject3D('camera') this.ground = document.getElementById('ground') this.rayOrigin = new THREE.Vector2(0, 0) this.cursorLocation = new THREE.Vector3(0, 0, 0) // 新增状态变量,标记树模型是否已生成 this.treeSpawned = false this.el.sceneEl.addEventListener('click', (event) => { // 仅当未生成过树模型时才执行创建流程 if (!this.treeSpawned) { const newElement = document.createElement('a-entity') newElement.setAttribute('position', this.el.object3D.position) const randomYRotation = Math.random() * 360 newElement.setAttribute('rotation', `0 ${randomYRotation} 0`) newElement.setAttribute('visible', 'false') newElement.setAttribute('scale', '0.0001 0.0001 0.0001') newElement.setAttribute('gltf-model', '#treeModel') newElement.setAttribute('shadow', {receive: false}) this.el.sceneEl.appendChild(newElement) newElement.addEventListener('model-loaded', () => { newElement.setAttribute('visible', 'true') newElement.setAttribute('animation', { property: 'scale', to: '10 10 10', easing: 'easeOutElastic', dur: 800, }) }) // 标记为已生成,后续点击不再触发创建 this.treeSpawned = true } }) }
方案二:DOM查询检查已存在实体
如果不想维护额外状态变量,也可以每次点击时直接查询场景中是否已有使用#treeModel的实体,存在则跳过创建逻辑:
修改后的点击事件部分代码:
this.el.sceneEl.addEventListener('click', (event) => { // 查询场景中是否已存在目标模型实体 const existingTree = this.el.sceneEl.querySelector('[gltf-model="#treeModel"]') if (existingTree) return // 已存在则直接返回,不执行后续创建 // 原模型创建逻辑保持不变 const newElement = document.createElement('a-entity') newElement.setAttribute('position', this.el.object3D.position) const randomYRotation = Math.random() * 360 newElement.setAttribute('rotation', `0 ${randomYRotation} 0`) newElement.setAttribute('visible', 'false') newElement.setAttribute('scale', '0.0001 0.0001 0.0001') newElement.setAttribute('gltf-model', '#treeModel') newElement.setAttribute('shadow', {receive: false}) this.el.sceneEl.appendChild(newElement) newElement.addEventListener('model-loaded', () => { newElement.setAttribute('visible', 'true') newElement.setAttribute('animation', { property: 'scale', to: '10 10 10', easing: 'easeOutElastic', dur: 800, }) }) })
两种方案对比
- 方案一性能更优:状态变量检查是内存操作,无需遍历DOM,适合频繁点击的场景。
- 方案二更灵活:无需维护额外变量,若后续有删除模型后允许重新生成的需求,无需修改状态逻辑。
内容的提问来源于stack exchange,提问作者Jesse
相关产品推荐
相关产品推荐

