首頁 > 軟體

關於vue中使用three.js報錯的解決方法

2022-03-05 13:00:11

前言

最近在學習three.js,同時也學習一下vue3,然後就出現問題了,報錯直接用不了,錯誤資訊如下:

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]')

這個是什麼鬼???相信大家都把錯誤資訊複製到百度搜了一下解決方案吧?遇到問題的人並不多,解決方案就是把scene、mesh 啥的放到全域性變數中,不放到data中,好的問題解決了。

我這樣寫是不是有點水文的嫌疑?作為一個成熟的程式設計師怎麼能水文呢?我得找到為什麼會出現這個問題才行,於是我花了兩個小時找到問題所在,也是怪自己不夠專業,不然應該花不了兩個小時。

1. vue的問題?

眾所周知,vue3是通過Proxy實現的資料雙向繫結,vue2是通過defindeProperty實現的資料雙向繫結,vue2的原始碼我也看過,應該也是會有這個問題的,因為在開發模式下面,如果瀏覽器支援Proxy還是會用Proxy,我沒有用vue2去嘗試,大家可以自行去嘗試,不出意外也會有這個問題。
上面說了一堆,就是為了引出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)。當屬性不可設定時,不能在資料和存取器屬性型別之間切換。
當試圖改變不可設定屬性(除了 value 和 writable 屬性之外)的值時,會丟擲TypeError,除非當前值和新值相同。

也就是說之前定義了configurable為false,就不能再將configurable改為true了,那怎麼辦?我說了問題當然是要給你解決的。

5. 解決

之前在網上查了,全域性變數來處理,但是我使用的vue啊,我當然是希望將它定義到data中的,但是定義到data中就會自動生成代理,那就只能從原始碼入手了。 我也就不講我是怎麼去找原始碼的,我直接上解決之後的吧,在node_modulesthreebuildthree.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要這樣處理這個變數,這個就看自己是怎麼處理的,我這次只處理這個問題。

總結

到此這篇關於vue中使用three.js報錯解決的文章就介紹到這了,更多相關vue使用three.js報錯內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com