Vue響應(yīng)式原理深入解析及注意事項(xiàng)
前言
Vue最明顯的特性之一便是它的響應(yīng)式系統(tǒng),其數(shù)據(jù)模型即是普通的 JavaScript 對象。而當(dāng)你讀取或?qū)懭胨鼈儠r(shí),視圖便會(huì)進(jìn)行響應(yīng)操作。文章簡要闡述下其實(shí)現(xiàn)原理,如有錯(cuò)誤,還請不吝指正。下面話不多說了,來隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
響應(yīng)式data
<div id = "exp">{{ message }}</div> const vm = new Vue({ el: '#exp', data: { message: 'This is A' } }) vm.message = 'This is B' // 響應(yīng)式 vm._message = 'This is C' // 非響應(yīng)式
上述代碼中,data是Vue實(shí)例的數(shù)據(jù)對象,當(dāng)實(shí)例初始化時(shí),Vue 會(huì)遍歷 data 中的所有屬性,并且使用 Object.definePropery 把這些屬性全都轉(zhuǎn)為 getter/setter ,從而讓 data 的屬性能夠響應(yīng)數(shù)據(jù)變化。另外,Object.defineProperty 是 ES5 中一個(gè)無法 shim(墊片) 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器的原因。對象必須是純粹的對象 (含有零個(gè)或多個(gè)的 key/value 鍵值對):瀏覽器 API 創(chuàng)建的原生對象。所以,在data中聲明過的message是響應(yīng)式數(shù)據(jù),而由于_message是在data外使用 Vue 實(shí)例增加的數(shù)據(jù),所以亦不屬于響應(yīng)式。
關(guān)于Object.definePropery
Object.defineProperty()
方法會(huì)直接在一個(gè)對象上定義一個(gè)新屬性,或者修改一個(gè)對象的現(xiàn)有屬性,并返回這個(gè)對象。這個(gè)API是實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)的關(guān)鍵所在。
Syntax: Object.defineProperty(obj, prop, descriptor)
- obj: 要定義屬性的對象
- prop: 要定義或修改的屬性的名稱
- descriptor: 將被定義或修改的屬性描述符。
Tips: 要知道ECMAScript中有兩種屬性:數(shù)據(jù)屬性和訪問器屬性。這里的descriptor可取值有數(shù)據(jù)屬性和訪問器屬性。
數(shù)據(jù)屬性: 包含一個(gè)數(shù)據(jù)值的位置,在此位置可以進(jìn)行讀寫操作,有以下特性:
- [[Configurable]]:對屬性的操作可配置性開關(guān),如刪除,修改。默認(rèn)值為true。
- [[Enumberble]]:是否可枚舉(通過for-in)。默認(rèn)值為true。
- [[Writable]]:能否修改屬性的值。默認(rèn)值為true。
- [[value]]:包含這個(gè)屬性的數(shù)據(jù)值,讀取時(shí)從該位置讀,寫入時(shí)把新值存到該位置。默認(rèn)值為undefined。
訪問器屬性: 不包含數(shù)據(jù)值,包含一個(gè)函數(shù)對(getter/setter)。特性如下:
- [[Configurable]]:對屬性的操作可配置性開關(guān),如刪除,修改。默認(rèn)值為true。
- [[Enumberble]]:是否可枚舉(通過for-in)。默認(rèn)值為true。
- [[Get]]:讀取屬性時(shí)調(diào)用的函數(shù)。默認(rèn)值為undefined。
- [[Set]]:寫入屬性時(shí)調(diào)用的函數(shù)。默認(rèn)值為undefined。
Tips: 在讀取訪問器屬性時(shí),就會(huì)調(diào)用getter函數(shù),該函數(shù)負(fù)責(zé)返回有效的值;在寫入訪問器屬性時(shí),會(huì)調(diào)用setter函數(shù)
并傳入新值,該函數(shù)負(fù)責(zé)決定如何處理數(shù)據(jù),但是這兩個(gè)函數(shù)不一定非要同時(shí)存在。Vue便是利用getter/setter這一特性來實(shí)現(xiàn)的響應(yīng)系統(tǒng)。
示例代碼:
// 定義一個(gè)book對象,_year和edition都屬于數(shù)據(jù)屬性。 var book = { _year : 2004, edition : 1 }; // 對book對象創(chuàng)建 year 訪問器屬性。 Object.defineProperty(book, "year",{ // 讀取 year 訪問器屬性時(shí),get() 方法返回 _year 的值。 get : function () { console.info(this._year, 'get'); // 2004 return this._year; }, // 寫入 year 訪問器屬性時(shí),set() 方法對新值進(jìn)行操作。 set : function (newValue) { if (newValue > 2004) { this._year = newValue; console.info(this._year, 'set') // 2005 this.edition += newValue - 2004; } } }); // 讀取 year 訪問器屬性時(shí)會(huì)返回_year的值。 book.year; // 寫入 year 訪問器屬性時(shí)會(huì)調(diào)用set() 函數(shù),進(jìn)行操作。 book.year = 2005; console.info(book.edition) // 2 console.info(book) // 此處藏有彩蛋。
watcher
官方表述:每個(gè)組件實(shí)例都有相應(yīng)的 watcher 實(shí)例對象,它會(huì)在組件渲染的過程中把屬性記錄為依賴,之后當(dāng)依賴項(xiàng)的 setter 被調(diào)用時(shí),會(huì)通知 watcher 重新計(jì)算,從而致使它關(guān)聯(lián)的組件得以更新。
如下圖所示:
Tips:模板中每個(gè)指令/數(shù)據(jù)綁定都有一個(gè)對應(yīng)的 watcher 對象。其中 watcher扮演的角色相當(dāng)于是一個(gè)紐帶,這個(gè)紐帶的作用就是依賴收集。
變化檢測
1·(Object.observe的廢棄),Vue不能檢測對象屬性的添加或刪除,因此屬性必須在data對象上,但是可以使用Vue.set(Object,key,value)
來將響應(yīng)屬性添加到對象上 (vm.$set
實(shí)例方法Vue.set
全局方法)。
2.使用(Object.assign()
或者_.extend()
)方法添加屬性,不會(huì)觸發(fā)更新,這時(shí)3建議使用oldobject=Object.assign({},oldobject,{key1:value1,key2:value2})
3.Vue不允許動(dòng)態(tài)添加 根級(jí)響應(yīng)式屬性,所有初始實(shí)例必須聲明(空值也需要)
4.在數(shù)據(jù)變化之后立即使用 vm.$nextTick(calllback)
實(shí)現(xiàn)在Dom更新后操作
文中還有部分深層細(xì)節(jié)沒有講述到,后續(xù)我也會(huì)接著更新系列文章來進(jìn)一步深深深究vue底層的響應(yīng)式原理,SYNT。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
基于vue-cli配置lib-flexible + rem實(shí)現(xiàn)移動(dòng)端自適應(yīng)
這篇文章主要介紹了基于vue-cli配置lib-flexible + rem實(shí)現(xiàn)移動(dòng)端自適應(yīng),需要的朋友可以參考下2017-12-12vue項(xiàng)目中openlayers繪制行政區(qū)劃
這篇文章主要為大家詳細(xì)介紹了vue項(xiàng)目中openlayers繪制行政區(qū)劃,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12webpack開發(fā)vue-cli的項(xiàng)目實(shí)踐
本文主要介紹了webpack開發(fā)vue-cli的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Vue使用mind-map實(shí)現(xiàn)在線思維導(dǎo)圖
Vue中的Mind-Map通常是指使用Vue.js這個(gè)前端框架構(gòu)建的思維導(dǎo)圖組件或庫,它可以幫助開發(fā)者在Web應(yīng)用中創(chuàng)建動(dòng)態(tài)、交互式的思維導(dǎo)圖,讓用戶可以直觀地組織信息和結(jié)構(gòu)化數(shù)據(jù),本文介紹了Vue使用mind-map實(shí)現(xiàn)在線思維導(dǎo)圖,需要的朋友可以參考下2024-07-07Vue引入路徑正確但一直報(bào)錯(cuò)問題:Already included file name&n
這篇文章主要介紹了Vue引入路徑正確但一直報(bào)錯(cuò):Already included file name ‘××ב differs from file name ‘××ב only in casing.具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12解決vue中數(shù)據(jù)更新視圖不更新問題this.$set()方法
這篇文章主要介紹了解決vue中數(shù)據(jù)更新視圖不更新問題this.$set()方法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06vue項(xiàng)目打包之后接口出現(xiàn)錯(cuò)誤的問題及解決
這篇文章主要介紹了vue項(xiàng)目打包之后接口出現(xiàn)錯(cuò)誤的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04vue路由結(jié)構(gòu)可設(shè)一層方便動(dòng)態(tài)添加路由操作
這篇文章主要介紹了vue路由結(jié)構(gòu)可設(shè)一層方便動(dòng)態(tài)添加路由操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08