You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 19:21:40