最近在 Vue 專案裡面編寫一個地圖元件,發現如果把地圖例項掛載到 data 中,會報錯。
程式碼如下:
export default {
data () {
return {
newMap: null
}
},
mounted () {
this.$nextTick(e=>{
this.newMap = new maptalks.Map(...)
})
}
}
複製程式碼
錯誤資訊如下:
通過在控制檯中列印 data 中的資料,發現 Vue 給所有的屬性都加上 setter/getter ( chrome 控制檯會直接列印原始的 object,而重寫了 setter/getter 的 object 將會用 "(...)" 代替 )。這個時候恍然大悟,原來 Vue data 中會重寫變數的 getter/setter,上面的錯誤就出現在 Vue 重寫地圖例項物件的 getter/setter 時。Vue 重寫 object 的 setter/getter 是為了跟蹤物件,實現響應式。地圖例項這樣的複雜物件沒有必要跟蹤,以下是幾種可以避免 Vue 的 walk 過程的解決方案。
一、Object.freeze
地圖例項仍然掛到 data 上但是使用 Object.freeze 來告訴 Vue 不要監聽
...
let map = new maptalks.Map(...)
this.newMap = Object.freeze(map)
複製程式碼
此方法可以避免 Vue 的 walk 錯誤,但是,我們儲存地圖例項到 data 中是為了方便後續呼叫,如果使用了 Object.freeze ,後面對地圖例項操作如:
this.newMap.setCursor('crosshair')
複製程式碼
會報錯,錯誤資訊如下:
二、定義成區域性變數,放到外面
let newMap = null
export default {
data () {
return {
}
},
mounted () {
this.$nextTick(e=>{
newMap = new maptalks.Map(...)
})
}
}
複製程式碼
此方法可以避免 Vue 的 walk 錯誤,但如果元件有多個例項的話, 會共享同一個 newMap,和之前掛在 data 上的邏輯並不完全等價。
三、變數名以 _ 開頭
export default {
data () {
return {
/* eslint-disable*/
_newMap: null
/* eslint-enable */
}
},
mounted () {
this.$nextTick(e=>{
this._newMap = new maptalks.Map(...)
})
}
}
複製程式碼
此方法可以避免 Vue 的 walk 錯誤,同時不影響後面對地圖例項進行操作,此方案為本次選用的方案。
四、不預先定義變數,直接掛載到 this 上
export default {
data () {
return {
}
},
mounted () {
this.$nextTick(e=>{
this.newMap = new maptalks.Map(...)
})
}
}
複製程式碼
此方法也可以避免 Vue 的 walk 錯誤,同時也不影響後面對地圖例項進行操作,但本人喜歡在 Vue 中變數都定義到 data 中,便於管理。