Aframe中点击按钮无法更换纹理问题求助
问题分析
你遇到的addEventListener of undefined错误,核心原因有两个:
- jQuery点击回调里的
this指向的是触发点击的.radisiDOM元素,不是AFRAME组件实例,所以this.el根本不存在; - 点击按钮时重复监听
model-loaded完全没必要——模型已经加载完成了,这个事件只会在模型首次加载时触发一次。
另外还有两个容易忽略的细节:
- 你没有保存目标材质的引用,点击时无法直接找到要修改的材质;
- 更新纹理后没有告诉Three.js材质需要重新渲染,即使纹理加载了也不会显示变化。
修正后的完整代码
1. 重构AFRAME注册组件
首先修改组件,在模型加载完成后保存目标材质的引用,方便后续点击时直接操作:
AFRAME.registerComponent('example', { init: function() { // 初始化变量,保存要修改的材质 this.targetMaterial = null; const el = this.el; el.addEventListener('model-loaded', function(e) { e.detail.model.traverse((child) => { if (child instanceof THREE.Mesh && child.material.name === "Craem") { // 将目标材质保存到组件实例上 this.targetMaterial = child.material; // 加载初始纹理 const initialTexture = new THREE.TextureLoader().load("assets/img/choco.png"); this.targetMaterial.map = initialTexture; // 标记材质需要更新,Three.js才会渲染新纹理 this.targetMaterial.needsUpdate = true; } }.bind(this)); // 绑定this到组件实例,确保内部this指向组件 }.bind(this)); } });
2. 修改点击事件逻辑
直接获取模型实体和组件实例,用之前保存的材质引用更新纹理:
$(".radisi").click(function() { // 获取模型对应的AFRAME实体 const modelEl = document.querySelector("#newmod"); // 获取我们注册的example组件实例 const exampleComp = modelEl.components.example; // 确保材质已经被正确保存 if (exampleComp && exampleComp.targetMaterial) { // 异步加载新纹理,加载完成后再赋值 new THREE.TextureLoader().load("assets/img/tri.png", (newTexture) => { exampleComp.targetMaterial.map = newTexture; // 必须设置needsUpdate,否则Three.js不会更新渲染 exampleComp.targetMaterial.needsUpdate = true; }); } });
关键要点解释
- 修正
this指向问题:jQuery点击回调里的this是触发点击的DOM元素,所以我们要直接通过document.querySelector获取模型实体,再拿到组件实例; - 保存材质引用:在模型加载完成后,把要修改的材质保存到组件实例的
targetMaterial属性上,后续点击时不用再遍历模型; needsUpdate = true:Three.js的材质默认不会自动检测纹理变化,必须手动设置这个属性,通知渲染器重新渲染材质;- 异步加载纹理:
TextureLoader.load是异步操作,用回调确保纹理加载完成后再赋值,避免出现纹理未加载就更新的问题。
内容的提问来源于stack exchange,提问作者andy ram
相关产品推荐
相关产品推荐

