VUE3 + Three.js 坑
1. 问题描述
将scene、camera、renderer、controls等变量用reactive变成响应式时,页面渲染会报错:
three.module.js?5a89:24471 Uncaught TypeError:
'get' on proxy: property 'modelViewMatrix' is a read-only and
non-configurable data property on the proxy target but the proxy did not
return its actual value (expected '#<Matrix4>' but got '[object Object]')
at renderObject (three.module.js?5a89:24471)
at renderObjects (three.module.js?5a89:24458)
at Proxy.WebGLRenderer.render (three.module.js?5a89:24258)
at animate (HelloWorld.vue?fdab:192)
2. 问题原因
Vue3的响应式原理是通过Proxy实现的,Proxy的get方法会拦截对象的读取操作,而three.js的源码中有很多属性是只读的,比如modelViewMatrix、normalMatrix等,这些属性在three.js的源码中是通过Object.defineProperty定义的,所以Proxy的get方法会拦截这些属性的读取操作,导致页面渲染报错。
在使用Proxy时,当属性存在属性特性configurable: false, value: undefined,时,则取其属性值时会报错
例如:
const handle = {
get() {
return 1;
},
};
const obj = Object.create(null);
Object.defineProperty(obj, 'a', {
configurable: false,
});
Object.defineProperty(obj, 'b', {
value: undefined,
});
Object.defineProperty(obj, 'c', {
configurable: true,
value: 'c',
});
const proxy = new Proxy(obj, handle);
console.log(proxy.a); // 报错TypeError: 'get' on proxy: property 'a' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected 'undefined' but got '1')
console.log(proxy.b); // 报错Uncaught TypeError: 'get' on proxy: property 'b' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected 'undefined' but got '1')
console.log(proxy.c); // 1
3. 解决方案
- 将scene、camera、renderer、controls等对象用全局var声明,不要reactive,这样就不会触发Proxy的get方法,也就不会报错了。
- 在添加一些场景的时候,场景可以用ref定义。添加的时候用toRaw转一下,例如:
scene.add(toRaw(mesh.value))
renderer.value.render(toRaw(scene.value), camera.value);
如果没有了响应式,用Vue3还有什么意义呢?
长风破浪会有时,直挂云帆济沧海