vue是響應式的嗎(vue響應式原理是什么)
大家好!今天讓創(chuàng)意嶺的小編來大家介紹下關于vue是響應式的嗎的問題,以下是小編對此問題的歸納整理,讓我們一起來看看吧。
創(chuàng)意嶺作為行業(yè)內(nèi)優(yōu)秀企業(yè),服務客戶遍布全國,相關業(yè)務請撥打175-8598-2043,或微信:1454722008
本文目錄:
一、vue2數(shù)據(jù)響應式原理
vue2響應式原理由 Observer 類, Dep 類和 Watcher 類互相調(diào)用實現(xiàn), Observer 類是把一個普通的object類變成每一層都能相應的類, Dep 類的作用是添加,移除,通知和收集訂閱者, Watcher 類是訂閱者,主要功能是把當數(shù)據(jù)改變的時候,去調(diào)用回調(diào)函數(shù),修改dom節(jié)點
那么是怎么實現(xiàn)響應式的呢,首先是一個函數(shù),要先轉(zhuǎn)換為可響應的,那就需要用到 Observer 類
這個 observe 函數(shù)就是對 Observer 類做多了一層封裝
而 Observer 類是通過 Object.defineProperty 來監(jiān)控數(shù)據(jù)的獲取和改變的
關鍵在于 defineReactive 方法,這個方法是對 Object.defineProperty 做了一層封裝,并且對對象的每一層做遞歸調(diào)用,實現(xiàn)了每一層都有響應監(jiān)控
但是是怎么知道現(xiàn)在要保存哪一個 Watcher 實例到訂閱者數(shù)組里面的呢?其實就是用了這個 Dep.target , Dep.target 相當于 window.target ,全局只有一個,全局也能訪問
首先得先講一講 Watcher 類,我們先回到上面的index.js,對象要讓 Watcher 類進行監(jiān)聽,而 Watcher 有3個參數(shù),第一個是監(jiān)聽的對象,第二個是監(jiān)聽的屬性,比如 a.b.c.d ,第三個是屬性改變后觸發(fā)的回調(diào)函數(shù)
先來講一下 parsePath ,這個在工具類里,作用是訪問 a.b.c.d 這種鏈式屬性
首先是觸發(fā)了 Watcher 的 get() 方法,把當前實例保存在了 Dep.target 里面
然后在調(diào)用 parsePath 獲取屬性值的過程中,會挨個訪問響應對象的屬性,就會觸發(fā)相應的 getter ,我們回到 defineReactive.js ,可以發(fā)現(xiàn)這時候相應屬性的 getter 就會把 Dep.target 也就是相應的 Watcher 的實例保存在了 Dep 類的訂閱者數(shù)組里面
最后,在改變屬性的時候,相應屬性的 setter 就會通知之前已經(jīng)保存的訂閱者數(shù)組,遍歷觸發(fā)回調(diào)
二、【手把手教你搓Vue響應式原理】(一)初識Vue響應式
在講這個之前,首先要明白一點,這個所謂的響應式,其實本身就是對 MVVM 的理解。
MVVM 其實就是所謂的 Modal View ViewModal 。
簡單理解,就是你的 data 中的數(shù)據(jù),和 template 模板中的界面,本身就是兩個東西。
但是, Vue 給你做了一層中間的 ViewModal ,讓視圖上的改變能反映到 data 中, data 中的改變能反映到視圖上。
在這個反映過程中,ViewModal就是視圖和數(shù)據(jù)的一個橋梁。
同樣是讓 a + 1 。
在 Vue 中,這個橋梁是你看不見的,因為 Vue 都幫你完成了視圖和數(shù)據(jù)的變化傳遞。
而 React 就是侵入式的,因為要顯式地聲明 setState ,通過它,來設置變量的同時,設置視圖的改變。
所以,所謂的侵入式,其實就是對于橋梁的侵入。
所以, Vue 的神奇之處就在于,不需要我們手動地顯示調(diào)用 setState ,也就是這個橋梁, Vue 已經(jīng)幫我們橋接上了。
要讓 data 改變的同時,視圖也發(fā)生改變,所以,問題的所在,就是我們需要監(jiān)聽,什么時候,這個變量發(fā)生了變量。
然而, ES5 中,就有那么一個特性,可以做到對于數(shù)據(jù)的劫持(監(jiān)聽)。
它就是 Object.defineProperty 。
Object.defineProperty( obj, prop, descriptor ) 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性,并返回此對象,與此同時,它可以對 對象的一些額外底層的屬性進行設置 。例如可以設置 writable , enumerable , configurable 等屬性。
后面的額外屬性設置,才是我們使用它的重點。
但是,我們使用的不是上面的幾個屬性,最主要的還是它的 get set ,可以對屬性值的獲取和設置操作進行攔截。
get主要是可以對值的獲取進行攔截,,它必須要傳入一個 return ,并且, 該函數(shù)的返回值會被用作屬性的值 。我們可以來看一個例子:
由于設置了 get ,所以,輸出 a.name 的時候直接會被攔截,走 get() 中的 return 所以,此時, a.name 的值應該是 你已經(jīng)被攔截了!。
set主要是可以對值的設置進行攔截,該方法會接受一個參數(shù),那就是 被賦予的新值 。我們可以來看一個例子:
由于設置了 set ,所以,設置值的時候會被攔截,走 set() 中的方法。
所以, Vue 能自動獲取data中的改變,反映到視圖的原因,就是有對于變量的獲取和設置的劫持,當變量發(fā)生改變的同時, Vue 能在第一時間知道,并且對視圖做出相應的改變操作。
而這把鑰匙就是 Object.defineProperty 。
【尚硅谷】Vue源碼解析之數(shù)據(jù)響應式原理
Object.defineProperty() - MDN
三、vue數(shù)組響應式原理
vue2中Object.defineProperty響應式只對對象有效,對數(shù)組無效,所以對數(shù)組做額外處理。我們知道,會改變數(shù)組本身的方法只有7個:sort, push, pop, slice, splice, shift, unshift,所以可以通過重寫這些方法來達到數(shù)組響應式
解決方案:
1. 找到數(shù)組原型
2. 覆蓋那些能夠修改數(shù)組的更新方法,讓他們在修改數(shù)組同時,還可以通知更新
3. 將得到的新的原型設置到數(shù)組實例原型上
4. 對數(shù)組內(nèi)部元素實現(xiàn)響應式
// 實現(xiàn)數(shù)組響應式// 1. 替換數(shù)組原型中7個方法constoriginalProto=Array.prototype// 克隆體原數(shù)組原型constarrayProto=Object.create(originalProto)// 可修改數(shù)組的7個方法 , 'sort'constchangeMethods=['push','pop','shift','unshift','slice','splice','sort']// 2. 在克隆的原型上,覆蓋那些能夠修改數(shù)組的更新方法,讓他們在修改數(shù)組同時,還可以通知更新changeMethods.forEach(method=>{arrayProto[method]=function(){// 進行原始操作originalProto[method].apply(this,arguments)// 覆蓋操作:增加更新通知console.log(`數(shù)組正在執(zhí)行${method}方法`);}})// 對象響應化functiondefineReactive(obj,key,value){Object.defineProperty(obj,key,{get(){console.log('獲取'+key);returnvalue},set(newVal){if(newVal!==value){// console.log(newVal);// console.log(JSON.stringify(obj[key]));console.log(`正在改變${key}值:從${obj[key]}變?yōu)?{newVal}`)value=newVal}}})}functionobserver(obj){// 不是對象或者為null,不做響應式,結(jié)束if(typeofobj!=='object'||obj===null)return;// 如果是數(shù)組,修改其實例的原型if(Array.isArray(obj)){// 3. 將得到的新的原型設置到數(shù)組實例原型上obj.__proto__=arrayProto// 4. 對數(shù)組內(nèi)的元素,同樣進行響應化for(leti=0;i<obj.length;i++){// console.log(obj[i]);observer(obj[i])}// 如果是對象}else{Object.keys(obj).forEach(key=>{console.log(obj,key,obj[key]);defineReactive(obj,key,obj[key])})}}obj=[{a:1},2,7,5,3]observer(obj)obj.push(4)// 數(shù)組正在執(zhí)行push方法obj.pop()// 數(shù)組正在執(zhí)行pop方法obj[0].a=2// 獲取a // 正在改變a值:從1變?yōu)?obj.sort()// 數(shù)組正在執(zhí)行sort方法console.log(obj);// [ 2, 3, 5, 7, { a: [Getter/Setter] } ]console.log(obj[4].a);// 獲取a // 2
鏈接:https://www.jianshu.com/p/886ac356c13d
四、vue2響應式原理總結(jié)
vue組件實例化時,會對data屬性深度遍歷(遇到數(shù)組或者對象)為每一個屬性添加數(shù)據(jù)劫持。數(shù)據(jù)劫持就是使用Object.defineProperty(de fai in pro pu tei)方法添加get/set方法。
在這個過程中會實例化一個Dep類。
1.在get攔截器里觸發(fā)dep實例的depend方法,進行依賴收集,實質(zhì)是在dep的實例屬性sub數(shù)組中添加依賴這個屬性的watcher實例。
2.在set攔截器里觸發(fā)dep實例的notify方法,對收集到的所有依賴派發(fā)更新,(watcher的update方法)
vue組件實例化時會實例化一個渲染watcher,渲染watcher實例化過程會做兩件事情。
1.創(chuàng)建vnode,在這個過程中,訪問了data屬性,觸發(fā)了get方法,完成了依賴收集。
2.觸發(fā)了子組件的實例化,子組件實例化又會重復上述數(shù)據(jù)劫持的過程。
這個過程就是對組件樹的深度遍歷。
結(jié)合組件生命周期來看整個過程,父組件會先觸發(fā)created鉤子,子組件后觸發(fā)created鉤子。而子組件mouted鉤子會先執(zhí)行,父組件的mouted鉤子后執(zhí)行。
分步驟記憶
1、實現(xiàn)頁面不刷新的原理
2、頁面視圖刷新的原理
實現(xiàn)頁面不刷新
1.hash
2.history
3.abstract:支持所有 JavaScript 運行環(huán)境,如 Node.js 服務器端。如果發(fā)現(xiàn)沒有瀏覽器的 API,路由會自動強制進入這個模式。
1.hash(哈希模式),#符號后邊是瀏覽器行為,在改變的時候不對頁面進行刷新(重新請求URL)(監(jiān)聽hashChange事件)
2.history模式,H5新增了pushState,replaceState連個新API,可以修改歷史記錄卻不會使瀏覽器刷新頁面。
視圖更新原理
其原理就是vue的響應式更新dom的原理,m => v
m是數(shù)據(jù),也就是在vue-router install時在根組件(root vue component)添加了_route屬性,在匹配到對應路由后更新了_route屬性值,繼而觸發(fā)了該屬性值的渲染watcher,在繼而觸發(fā)dom更新。
兩種模式的不同
1.部署時,history模式需要服務端處理所有可能的路徑(例如配置nginx的配置文件),防止出現(xiàn)404。哈希模式則不需要。
2.URL表示不同。
v-model指令就是 v-bind:value 和 @input 的語法糖。
它即可以支持原生表單元素,也可以支持自定義組件
在自定義組件中其實際是這樣的:
它的實現(xiàn)通過自定義render函數(shù), 緩存了 vnode
Vue 在更新 DOM 時是異步執(zhí)行的,只要偵聽到數(shù)據(jù)變化,Vue 將開啟一個隊列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。
如果同一個 watcher 被多次觸發(fā),只會被推入到隊列中一次。在緩沖時會去除重復數(shù)據(jù)避免不必要的計算和 DOM 操作。
$nextTick(cb) 目的是在DOM 更新完成后傳入的回調(diào)函數(shù)再被調(diào)用。
以上就是關于vue是響應式的嗎相關問題的回答。希望能幫到你,如有更多相關問題,您也可以聯(lián)系我們的客服進行咨詢,客服也會為您講解更多精彩的知識和內(nèi)容。
推薦閱讀: