vue中使用three.js报错

简介: 在vue中使用threejs居然报错了,这是为什么?是vue的问题还是threejs的问题?锅居然甩到了es6的proxy上了,居然还和defineProperty脱不开关系,快来看看是怎么一回事吧!

最近在学习three.js,同时也学习一下vue3,然后就出现问题了,报错直接用不了,错误信息如下:

image.png

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 '#' but got '[object Object]')

这个是什么鬼???相信大家都把错误信息复制到百度搜了一下解决方案吧?遇到问题的人并不多,解决方案就是把scenemesh 啥的放到全局变量中,不放到data中,好的问题解决了。


我这样写是不是有点水文的嫌疑?作为一个成熟的程序员怎么能水文呢?我得找到为什么会出现这个问题才行,于是我花了两个小时找到问题所在,也是怪自己不够专业,不然应该花不了两个小时。

1. vue的问题?

先思考一个问题,网上的解决方案为什么要将几个场景对象定义在全局中,而不能定义在vuedata中呢?全局和data中的变量有什么区别?应该就是全局的对象不是双向绑定的,data中的数据可以实现双向绑定,那么为什么双向绑定会出现这个问题呢?带着问题寻找答案
众所周知,vue3是通过Proxy实现的数据双向绑定,vue2是通过defineProperty实现的数据双向绑定。
尝试的使用了一下vue2没有发现这个问题,那么问题应该就是出现在vue3使用Proxy的问题上。
上面说了一堆,就是为了引出Proxy的异常情况,好了又可以学习一下Proxy的知识了

2. Proxy的异常情况

在使用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. Three.js 的问题

this.scene = new Scene();
this.scene.modelViewMatrix;

直接运行上面的代码,就会看到文首出现的错误,错误原因就是因为configurable设置为false,找到问题就要解决问题,是不是觉得直接使用defineProperty就可以解决了?
很抱歉,这个不行,再来学习一下defineProperty

4. defineProperty异常情况

MDN中是这样描述的

如果属性已经存在,Object.defineProperty()将尝试根据描述符中的值以及对象当前的配置来修改这个属性。如果旧描述符将其configurable 属性设置为false,则该属性被认为是“不可配置的”,并且没有属性可以被改变(除了单向改变 writable 为 false)。当属性不可配置时,不能在数据和访问器属性类型之间切换。
当试图改变不可配置属性(除了 valuewritable 属性之外)的值时,会抛出TypeError,除非当前值和新值相同。

也就是说之前定义了configurablefalse,就不能再将configurable改为true了,那怎么办?我说了问题当然是要给你解决的。

4. 解决

之前在网上查了,全局变量来处理,但是我使用的vue啊,我当然是希望将它定义到data中的,但是定义到data中就会自动生成代理,那就只能从源码入手了。
我也就不讲我是怎么去找源码的,我直接上解决之后的吧,在node_modules\three\build\three.module.js这个文件中,第7392行,里面的代码如下:

Object.defineProperties( this, {
   
   
 position: {
   
   
  configurable: true,
  enumerable: true,
  value: position
 },
 rotation: {
   
   
  configurable: true,
  enumerable: true,
  value: rotation
 },
 quaternion: {
   
   
  configurable: true,
  enumerable: true,
  value: quaternion
 },
 scale: {
   
   
  configurable: true,
  enumerable: true,
  value: scale
 },
 modelViewMatrix: {
   
   
  value: new Matrix4()
 },
 normalMatrix: {
   
   
  value: new Matrix3()
 }
} );

看到了吧,里面有一个modelViewMatrix属性,它没有设置configurable属性描述,也就是默认为false,加上就好了,改好了如下:

Object.defineProperties( this, {
   
   
 position: {
   
   
  configurable: true,
  enumerable: true,
  value: position
 },
 rotation: {
   
   
  configurable: true,
  enumerable: true,
  value: rotation
 },
 quaternion: {
   
   
  configurable: true,
  enumerable: true,
  value: quaternion
 },
 scale: {
   
   
  configurable: true,
  enumerable: true,
  value: scale
 },
 modelViewMatrix: {
   
   
  configurable: true,
  value: new Matrix4()
 },
 normalMatrix: {
   
   
  value: new Matrix3()
 }
} );

然后重启服务,就不会报错了,当然这种方式是有缺陷的,因为改了只是你本地的,你其他同事的代码并没有改,如果要升级three.js也会把改了的代码重新覆盖,同时也不知道为什么three.js要这样处理这个变量。
那么有没有更好的解决方案呢?答案当然是有的

5. 最佳解决方案

上面说的解决方案其实都不够正常,一般使用第三方库是不建议修改库的源码,因为你不知道会产生什么样的未知问题,同时需要考虑协同的问题,第三方库升级的问题等一系列的问题。
网上说的解决方案就是定义全局变量,全局变量无非就是失去了双向数据绑定,但是我们在使用的vue的时候,不管数据是不是响应式的,都是希望能用this给它点出来的,全局变量对应使用vue的用户来说肯定不是很优雅的,甚至让人感觉到难受,那么怎么样才能用this能点出来的同时让数据不是响应式的呢?
答案是在data中直接定义,废话说的有点多,直接上代码:

data() {
   
   
  // 场景对象
  this.scene = null;

  // 透视摄像机
  this.camera = null;

  // 渲染器
  this.webGLRender = null;
  return {
   
   };
},

好了,问题圆满解决,撒花!!!!

目录
相关文章
|
2月前
|
JavaScript 前端开发 开发者
VUE 开发——Node.js学习(一)
VUE 开发——Node.js学习(一)
72 3
|
1月前
|
JavaScript 前端开发 持续交付
构建现代Web应用:Vue.js与Node.js的完美结合
【10月更文挑战第22天】随着互联网技术的快速发展,Web应用已经成为了人们日常生活和工作的重要组成部分。前端技术和后端技术的不断创新,为Web应用的构建提供了更多可能。在本篇文章中,我们将探讨Vue.js和Node.js这两大热门技术如何完美结合,构建现代Web应用。
31 4
|
2月前
|
JavaScript 前端开发 开发工具
【Azure Developer】使用JavaScript通过SDK进行monitor-query的client认证报错问题
AADSTS90002: Tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' not found. Check to make sure you have the correct tenant ID and are signing into the correct cloud. Check with your subscription administrator, this may happen if there are no active subscriptions for the tenant.
|
3月前
|
JavaScript
Vue+element_Table树形数据与懒加载报错Error in render: “RangeError: Maximum call stack size exceeded“
本文讨论了在使用Vue和Element UI实现树形数据和懒加载时遇到的“Maximum call stack size exceeded”错误,指出问题的原因通常是因为数据中的唯一标识符`id`不唯一,导致递归渲染造成调用栈溢出。
106 1
Vue+element_Table树形数据与懒加载报错Error in render: “RangeError: Maximum call stack size exceeded“
|
3月前
|
JavaScript 前端开发 API
Vue学习笔记3:对比纯JavaScript和Vue实现数据更新的实时视图显示
Vue学习笔记3:对比纯JavaScript和Vue实现数据更新的实时视图显示
|
2月前
|
JavaScript 前端开发 应用服务中间件
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
164 0
|
2月前
|
JavaScript
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
46 0
|
2月前
|
JavaScript 前端开发
前端js,vue系统使用iframe嵌入第三方系统的父子系统的通信
前端js,vue系统使用iframe嵌入第三方系统的父子系统的通信
|
3月前
|
人工智能 JavaScript 索引
Duplicate keys detected: This may cause an update error.【Vue遍历渲染报错的解决】
这篇文章讨论了在Vue中进行列表渲染时遇到的“Duplicate keys detected”错误。这个错误通常发生在使用 `v-for` 指令渲染列表时,如果没有为每个循环项指定一个唯一的 `key` 属性,或者指定的 `key` 属性值重复了。文章提供了导致错误的原始代码示例,并给出了修正后的代码,通过在 `key` 绑定中加入索引确保 `key` 的唯一性。此外,文章还解释了为什么需要唯一 `key` 以及如何解决这个问题。
Duplicate keys detected: This may cause an update error.【Vue遍历渲染报错的解决】
|
2月前
|
JavaScript
Vue启动时报错的解决方案,以及解决相同路径跳转报错的问题
Vue启动时报错的解决方案,以及解决相同路径跳转报错的问题
257 0