vue 簡單剖析資料驅動以及注意事項

2021-09-17 05:36:04 字數 2735 閱讀 3306

今天同事在開發的時候,對陣列型別的資料進行賦值的時候發現檢視並未更新。原來我也遇到過當時解決方式是改變賦值的方式,也未深究其原理,在以後的開發中可能因為開發習慣比較好,也再沒出現過這種情況。今天就著這個問題剖析下vue的資料驅動,以及有哪些注意事項(文件中也說了,還是要經常刷文件,每刷一遍都有不同的理解)。

資料驅動的整體思路(可以這樣理解,原始碼的實現過程比這裡複雜很多):

對於宣告的變數,vue在資料例項化的時候都會新增乙個getter和setter,分別負責取值和賦值。

對於雙向繫結的變數,也就是在dom中繫結的變數,vue都會給他繫結乙個watcher。在賦值觸發setter的時候會觸發watcher,watcher會重新計算變數的值是否發生了改變,在監聽到變數發生變化時會操作具體的dom改變其繫結的變數來實現更新。

下面就按照上面的過程分析下是如何實現的以及為什麼會出現我同事出現的問題。

先講下getter/setter:

// 簡單實現

const data =

;object.

defineproperty

(data,

'names',,

set:

(newval)

=>})

;data.names;

//獲取資料

data.names =

['wang'];

//更新資料,引數是walsr (觸發了set)

data.names.push =

'wang'

;//獲取資料 (未觸發set)

data相當於vue中的vm.$data,get是乙個給names屬性(相當於宣告的names變數)提供 getter 的方法,set是乙個給屬性提供 setter 的方法(接受唯一引數)。觸發set的時候繼而觸發了watcher。到這裡同時也回答了為什麼vue不支援ie8及以下版本,因為vue用了defineproperty方法來實現監聽資料,而defineproperty只支援ie9及以上版本瀏覽器。

看上面的例子大致可以明白我同事出現的問題在**,就是沒有觸發變數相應的set同時也就沒觸發變數相應的watcher。這裡我也有個疑問,在這個簡單的例子中push並沒有觸發set,但vue是會監聽到push的。官方文件陣列更新檢測說明,文件說了能監聽到陣列的變異方法,至於我同事的問題就是沒有用對方法。

上面的整體思路正常理解起來沒問題,但是跟vue原始碼具體實現watcher還是有些區別的,我大致說一下我的理解吧,原始碼我理解的不是很全面,以下僅作參考。這裡沒有貼原始碼,只是我個人的理解,具體參考 vue 原始碼解析:深入響應式原理。

首先在vue例項化的時候會有乙個生命週期,其中乙個過程的就是呼叫 vm.initdata() 來處理 data 選項。

在 initdata 中使用了proxy 方法,它的功能就是遍歷 data 的 key,把 data 上的屬性(也就是在data中宣告的變數)**到 vm 例項上。 proxy 方法是通過 object.defineproperty 的 getter 和 setter 方法實現了**。這就是為什麼會講 getter 和 setter 。

initdata 在把變數**到vm例項上後會呼叫 observe(data, this) 方法來對 data 做監聽 。對於陣列、物件型別的變數,observe會對其每乙個屬性進行轉換,使它們都擁有 getter、setter 方法。到這裡為止每個變數以及其屬性都有了 getter、setter 方法,當變數被訪問或者更新時,我們就可以追蹤到這些變化。

observe下面有乙個 dep 類,在 getter 和 setter 方法呼叫時會分別呼叫 dep.depend 方法和 dep.notify 方法,depend 方法的功能是把當前 dep 的例項新增到當前正在計算的watcher 的依賴中,notify 方法功能時遍歷所有的 watcher,呼叫相應的 update 方法,以此來達到更新的作用。

上述過程最重要的就是:通過observe(底層還是基於defineproperty)實現了變數和watcher之間的關聯,watcher類再去實現相應dom的更新。watcher類的解析等我在深挖下原始碼在系統的梳理把,現在理解的可能不時很準確。

到這裡基本上整個資料驅動流程就介紹完了,下面說下資料驅動的注意事項

var vm =

newvue(}

})

陣列:當你利用索引直接設定乙個項時,例如:vm.items[0] = 'd'

陣列:當你修改陣列的長度時,例如:vm.items.length = 5

物件:當你新增或刪除物件屬性時:例如:vm.person.age = 33物件:當你使用object.assign()時:例如:object.assign(vm.person, )

相應的解決辦法:

vm.$set(vm.items, 0, 'd')或者vm.items.splice(0, 1, 'd')vm.items.splice(5)vm.$set(vm.person, 'age', 33)vm.person = object.assign({}, vm.person, )

Linux核心以及驅動技術 簡單

無論是vc還是vb,還是c 還是jsp php等等語言,在學習他們之前總是先來乙個hello world的例子,這個好像成了我們程式入門的必經之路。所以在驅動程式的學習上,也離不開這個步驟。但是驅動程式的開發是執行在核心空間的,而應用程式 是執行在使用者空間的,所以驅動程式的開發盒除錯和應用程式的開...

vue核心之資料驅動

資料驅動 vue最大的特點。資料驅動是通過 資料劫持結合發布者 訂閱者模式實現的。在vue中,所謂的資料驅動就是當資料發生變化的時候,使用者介面發生相應的變化,我們對檢視的修改,不會直接操作 dom 而是通過修改資料。它相比我們傳統的前端開發,如使用 jquery 等前端庫直接修改 dom,大大簡化...

Vue簡單介紹以及常用方法總結

vue.js 讀音 vju 類似於 view 是一套構建使用者介面的 漸進式框架。與其他重量級框架不同的是,vue 採用自底向上增量開發的設計。vue 的核心庫只關注檢視層,並且非常容易學習,非常容易與其它庫或已有專案整合。另一方面,vue 完全有能力驅動採用單檔案元件和 vue 生態系統支援的庫開...