摘要:觀察員由模板解析指令創(chuàng)建的觀察員負(fù)責(zé)模板中的更新視圖操作。觀察員種類目前了解情況來看主要分三類視圖指令的計(jì)算屬性的用戶自定義的
介紹
關(guān)于 Vue.js 的原理一直以來都是一個(gè)話題。經(jīng)過幾天的源碼學(xué)習(xí)和資料介紹,我將一些個(gè)人理解的經(jīng)驗(yàn)給寫下來,希望能夠與大家共勉。
簡單圖解 Vue.js 內(nèi)置對象 構(gòu)造實(shí)例對象附上GITHUB源碼地址, 如果有任何不解 可以在 文章下面提出或者寫下issue, 方便大家回答和學(xué)習(xí), 有興趣可以Star.
最后附上 LIVE DEMO
應(yīng)用創(chuàng)建時(shí)需要使用的構(gòu)造函數(shù)對象, data 為我們的數(shù)據(jù)模型
const vm = new Vue({ data: { foo: "hello world" } });數(shù)據(jù)雙向綁定 被觀察者 observe
被觀察對象,data屬性里的值的變化,get時(shí)檢查是否有新的觀察員需要加入觀察員集合, set時(shí)通知觀察員集合里的觀察員更新視圖,被觀察者有一個(gè)觀察員的集合對象。
觀察員集合對象 Dep一個(gè)觀察員的收集器, depend()負(fù)責(zé)將當(dāng)前的 Dep.target 觀察員加入觀察員集合, data 中的每一項(xiàng)數(shù)據(jù)都會(huì)有對應(yīng)的閉包dep對象, 數(shù)據(jù)對象會(huì)有一個(gè)內(nèi)置的dep對象,用來通知嵌套的數(shù)據(jù)對象變化的情況。
觀察員 watcher由模板解析指令創(chuàng)建的觀察員, 負(fù)責(zé)模板中的更新視圖操作。保留舊的數(shù)據(jù),以及設(shè)置鉤子函數(shù) update(), 等待被觀察者數(shù)據(jù)通知更新,對比新的value與舊數(shù)據(jù), 從而更新視圖。
數(shù)據(jù)代理 proxyData我們的關(guān)注點(diǎn)在與創(chuàng)建后的vm, 其 options.data, 被掛載至vm._data, 同時(shí)被代理至 vm 上, 以至于 vm._data.foo 等價(jià)于 vm.foo, 代理函數(shù)代碼如下:
const noop = function () {} const sharedPropertyDefinition = { enumerable: true, configurable: true, get: noop, set: noop } function proxy (target, sourceKey, key) { sharedPropertyDefinition.get = function proxyGetter () { return this[sourceKey][key] } sharedPropertyDefinition.set = function proxySetter (val) { this[sourceKey][key] = val } Object.defineProperty(target, key, sharedPropertyDefinition) } // initState 時(shí)執(zhí)行 initData function initData () { const keys = Object.keys(data) let i = keys.length while (i--) { const key = keys[i] // key不以 $ 或 _開頭 if (!isReserved(key)) { proxy(vm, `_data`, key) } } // do something }數(shù)據(jù)劫持 defineProperty
/** * Define a reactive property on an Object. */ function defineReactive(obj, key, val) { // 觀察員集合 const dep = new Dep(); // data 內(nèi)屬性描述 const property = Object.getOwnPropertyDescriptor(obj, key); // 屬性不可再次修改 if (property && property.configurable === false) { return; } // 屬性預(yù)定義 getter/setters const getter = property && property.get; const setter = property && property.set; // 如果val為對象, 獲取val的 被觀察數(shù)據(jù)對象 __ob__ let childOb = observe(val); Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { // 被觀察數(shù)據(jù)被使用時(shí), 獲取被觀察員最新的數(shù)據(jù) const value = getter ? getter.call(obj) : val // 觀察員在new時(shí)或使用 get()時(shí), 注入給被觀察員對象集合 if (Dep.target) { // 將當(dāng)前的 watcher 傳遞給 觀察員 dep.depend(); if (childOb) { // 將當(dāng)前的 watcher 傳遞給子對象的 觀察員 childOb.dep.depend(); } } return val; }, set: function reactiveSetter(newVal) { const value = getter ? getter.call(obj) : val; if (newVal === value || (newVal !== newVal && value !== value)) { return; } if (setter) { setter.call(obj, newVal); } else { val = newVal; } // 新value設(shè)置被觀察者對象 __ob__ childOb = observe(newVal); // 通知數(shù)據(jù)對象依賴的觀察員, 更新 update() dep.notify(); } }); }計(jì)算屬性介紹 初始化執(zhí)行過程
計(jì)算屬性的定義和使用
var vm = new Vue({ data: { firstname: "li", lastname: "yanlong" }, computed: { fullname () { return this.firstname + this.lastname; } } }); console.log(vm.fullname);核心代碼解讀
const computedWatcherOptions = {lazy: true}; function initComputed (vm, computedOptions) { // 創(chuàng)建計(jì)算屬性對應(yīng)的觀察員對象 // 獲取計(jì)算屬性時(shí)收集 內(nèi)置數(shù)據(jù)對象的 dep const watchers = vm._computedWatchers = Object.create(null) for (const key in computed) { const userDef = computed[key] const getter = typeof userDef === "function" ? userDef : userDef.get // create internal watcher for the computed property. watchers[key] = new Watcher( vm, getter || noop, noop, computedWatcherOptions ); if (!(key in vm)) { defineComputed(vm, key, userDef) } } } function defineComputed (target, key, userDef) { // 如果不為服務(wù)端渲染,則使用緩存value const shouldCache = !isServerRendering() // sharedPropertyDefinition 共享屬性配置 if (typeof userDef === "function") { sharedPropertyDefinition.get = shouldCache ? createComputedGetter(key) : userDef sharedPropertyDefinition.set = noop } else { sharedPropertyDefinition.get = userDef.get ? shouldCache && userDef.cache !== false ? createComputedGetter(key) : userDef.get : noop sharedPropertyDefinition.set = userDef.set ? userDef.set : noop } // 給 vm對象定義計(jì)算屬性 Object.defineProperty(target, key, sharedPropertyDefinition) } // 創(chuàng)建 function createComputedGetter (key) { return function computedGetter () { const watcher = this._computedWatchers && this._computedWatchers[key] if (watcher) { // 計(jì)算屬性的 watcher 有數(shù)據(jù)更新過, 重新計(jì)算 if (watcher.dirty) { watcher.evaluate() } // 視圖指令 使用了計(jì)算屬性 // 將計(jì)算屬性的watcher依賴傳遞給視圖指令的 watcher if (Dep.target) { // 源碼地址 // https://github.com/vuejs/vue/blob/master/src/core/observer/watcher.js#L210 watcher.depend() } return watcher.value } } }計(jì)算屬性知識(shí)點(diǎn)介紹
1. 計(jì)算屬性的 watcher 對象
計(jì)算屬性函數(shù)在讀取它本身的value時(shí), 使用一個(gè)watcher觀察員進(jìn)行代理. 通過對原始數(shù)據(jù)的劫持, 將watcher 觀察員添加到原始數(shù)據(jù)的dep依賴集合中.
2. deps的數(shù)據(jù)對象發(fā)生更新
舉例,如果firstname 或者 lastname 任意一個(gè)更新,那么就會(huì)設(shè)置計(jì)算屬性的watcher.dirty = true, 而當(dāng)其它指令或者函數(shù)使用,計(jì)算屬性會(huì)重新計(jì)算值,如果是視圖指令,還會(huì)重新該指令的watcher的數(shù)據(jù)對象依賴。
目前了解情況來看, 主要分三類
視圖指令的 watcher
計(jì)算屬性的 watcher
用戶自定義的 watcher
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/88829.html
摘要:至此它便作為一個(gè)唯一數(shù)據(jù)源而存在。改變中的狀態(tài)的唯一途徑就是顯式地提交。這樣使得可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而能夠?qū)崿F(xiàn)一些工具幫助更好地了解應(yīng)用背后的基本思想,借鑒了和參考源碼解讀一架構(gòu)入門教程狀態(tài)管理 準(zhǔn)備工作 1.下載安裝運(yùn)行 這里以2.0.0-rc.6為例官網(wǎng)github下載鏈接(對應(yīng)版本):https://github.com/vuejs/vuex...點(diǎn)擊下載到本地 ...
摘要:今年的月日,的版本正式發(fā)布了,其中核心代碼都進(jìn)行了重寫,于是就專門花時(shí)間,對的源碼進(jìn)行了學(xué)習(xí)。本篇文章就是源碼學(xué)習(xí)的總結(jié)。實(shí)現(xiàn)了并且將靜態(tài)子樹進(jìn)行了提取,減少界面重繪時(shí)的對比。的最新源碼可以去獲得。 Vue2.0介紹 從去年9月份了解到Vue后,就被他簡潔的API所吸引。1.0版本正式發(fā)布后,就在業(yè)務(wù)中開始使用,將原先jQuery的功能逐步的進(jìn)行遷移。 今年的10月1日,Vue的2...
前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁 https://github.com/muwoo/blogs歡迎訂閱。不過最近因?yàn)槭虑楸容^多,有一段時(shí)間沒有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...
前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁 https://github.com/muwoo/blogs歡迎訂閱。不過最近因?yàn)槭虑楸容^多,有一段時(shí)間沒有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...
前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁 https://github.com/muwoo/blogs歡迎訂閱。不過最近因?yàn)槭虑楸容^多,有一段時(shí)間沒有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...
閱讀 3190·2021-11-10 11:35
閱讀 1295·2019-08-30 13:20
閱讀 1117·2019-08-29 16:18
閱讀 2131·2019-08-26 13:54
閱讀 2155·2019-08-26 13:50
閱讀 955·2019-08-26 13:39
閱讀 2473·2019-08-26 12:08
閱讀 1951·2019-08-26 10:37