五、交互与控制器
5.1 光标(cursor)组件
光标允许用户通过“注视”或点击与物体交互:
<a-scene>
<a-camera>
<a-cursor id="cursor"
animation__click="property: scale; from: 0.1 0.1 0.1; to: 1 1 1; dur: 200; startEvents: click"
material="color: white; shader: flat"
position="0 0 -1"
geometry="primitive: ring; radiusOuter: 0.016; radiusInner: 0.005">
</a-cursor>
</a-camera>
<!-- 可交互的立方体 -->
<a-box position="0 1.5 -3" color="#FF0000"
event-set__click="_event: click; color: #00FF00">
</a-box>
</a-scene>
5.2 使用事件系统
A‑Frame 使用 DOM 事件进行组件间通信:
<!-- 触发事件 -->
<a-box id="trigger" event-set__click="_event: custom-event; target: #target"></a-box>
<!-- 接收事件 -->
<a-sphere id="target" event-set__custom-event="color: blue"></a-sphere>
// 在 JavaScript 中监听事件
document.querySelector('a-box').addEventListener('click', () => {
console.log('盒子被点击了')
})
5.3 在组件中发送/接收事件
AFRAME.registerComponent('my-component', {
init: function () {
// 发送自定义事件
this.el.emit('custom-event', { data: 'some data' })
// 监听自定义事件
this.el.addEventListener('custom-event', (evt) => {
console.log('收到事件', evt.detail)
})
}
})
六、自定义组件开发
A‑Frame 的真正强大之处在于其可扩展性。通过编写自定义组件,你可以实现任何 Three.js 能够做到的复杂功能。
6.1 自定义组件基础结构
一个标准的 A‑Frame 组件包含以下几个部分:
schema(模式):定义组件的属性及其类型
init():组件初始化时调用
update():当组件属性更新时调用
remove():组件被移除时调用
tick():每一帧调用,用于持续变化
最简组件示例:
AFRAME.registerComponent('hello-world', {
init: function () {
console.log('Hello, World!');
}
});
注册后,即可在 HTML 中使用:
<a-entity hello-world></a-entity>
6.2 带参数的组件
通过 schema 定义组件可以接收的数据:
AFRAME.registerComponent('log', {
schema: {
message: { type: 'string', default: 'Hello, World!' }
},
init: function () {
console.log(this.data.message);
}
});

6.3 组件生命周期方法
AFRAME.registerComponent('my-component', {
// 1. 定义组件数据模式
schema: {
color: { type: 'color', default: '#FFF' },
intensity: { type: 'number', default: 1.0 }
},
// 2. 初始化:组件首次附加到实体时调用(仅一次)
init: function () {
this.el.setAttribute('material', 'color', this.data.color);
},
// 3. 更新:属性变化时调用,init 后也会立即调用一次
update: function (oldData) {
// 检查颜色是否变化
if (oldData.color !== this.data.color) {
this.el.setAttribute('material', 'color', this.data.color);
}
},
// 4. 每帧调用:用于持续更新(如跟随、旋转)
tick: function (time, timeDelta) {
// 每秒旋转 1 弧度
this.el.object3D.rotation.y += 0.016;
},
// 5. 移除:组件被卸载时调用
remove: function () {
console.log('组件已卸载');
}
});
使用自定义组件:
<a-entity my-component="color: #FF0000; intensity: 0.8"></a-entity>
6.4 访问 Three.js 对象
在 A‑Frame 组件内部,你可以直接访问底层的 Three.js 对象:
AFRAME.registerComponent('animate-rotation', {
tick: function () {
// 获取实体的 Three.js 对象
const mesh = this.el.getObject3D('mesh');
if (mesh) {
mesh.rotation.y += 0.01;
}
}
});
6.5 组件间通信
A‑Frame 使用 DOM 事件进行组件间通信:
发送事件:
// 在组件中触发表面上物体的点击事件
this.el.emit('box-clicked', { id: this.el.id });
监听事件:
// 在另一个组件中监听该盒子上的事件
document.querySelector('#my-box').addEventListener('box-clicked', (evt) => {
console.log('盒子被点击了', evt.detail.id);
});