當前位置:首頁 » 操作系統 » vue源碼解讀

vue源碼解讀

發布時間: 2022-09-08 07:10:54

『壹』 vuejs源碼用了什麼設計模式,具體點的

最簡單的訂閱者模式

// Observer
class Observer {
constructor (data) {
this.walk(data)
}
walk (data) {
// 遍歷
let keys = Object.keys(data)
for(let i = 0; i < keys.length; i++){
defineReactive(data, keys[i], data[keys[i]])
}
}
}

function defineReactive (data, key, val) {
observer(val)

// dep 為什麼要在這里實例化, 就是為了實現, 對象每一層的 每一個key都有自己的一個訂閱實例, 比如 a.b 對應 dep1, a.c 對應dep2, 這里雖然都是let dep = new Dep()
// 但每次來到這個方法, dep都是獨立的, 會一直保留在內存. 這樣在每次調用set方法都能找到這個a.b對應的dep
// dep 這里會一直保存, 是因為閉包的關系, Object這個全局的函數, 引用了上層的作用域, 這個作用域包含了 dep, 除非Object = null, 或者退出瀏覽器, dep才會消失

//實例化之後, dep就有了被訂閱, 和發布消息的功能, dep不寫在這里也是可以的, 多定義一個全局函數, 每次obser的時候增加一個dep
let dep = new Dep()
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
//每次new Watch('a.b'), 都會先執行get方法, 進而來到這里, 觸發 dep.depend(), 這個dep就是 a.b 對應的 訂閱,
dep.depend()
return val
},
set: function (newVal) {
if(val === newVal){
return

『貳』 Vue入坑史,插件系統詳解

在談主題插件之前,我想先引出兩個關於 Vue 的問題,這也是我存在的兩個疑問,希望有人能夠幫忙解答。

如果你比較心急,可以直接跳到 Vue.use源碼解讀

這兩個是我最近在開發過程中遇到的問題,也沒有找到相關的答案,希望有誰能夠幫忙解答,在此先行謝過了。

Vue 的插件一般就是用來 擴展Vue的功能 。比如,當需要 Vue 實現 Ajax 請求功能,我們希望通過 this.$get(url) 的形式就可以發送一個 get 請求。那麼,我們就需要給 Vue 的實例添加一個 $get 方法, Vue 實例本身是沒有這個方法的。

Vue 的一些插件:

在創建 Vue 實例之前,通過全局方法 Vue.use() 來使用插件:

是不是很簡單,好像也沒有什麼好說的。

有時候,我們看到某些插件使用起來可能有些不一樣。比如使用 vuex :

其實本質上還是一樣的,也是通過 Vue.use() 方法注冊插件。只不過它有一個 store 對象,然後並將 store 對象作為 Vue 根實例的屬性,以便組件通過 this.$store 這種形式來訪問

其實當通過 Vue.use() 注冊插件時,內部會自動調用插件的 install() 方法。也就是說,插件必須要提供一個公開的 install() 方法,作為介面。該方法第一個參數是 Vue ,第二個參數是可選的 options 對象。

總結起來說,插件是一個對象。該對象要有一個公開的 install() 方法,那麼寫起來可能是這樣的:

在 install() 方法中,我們通過參數可以拿到Vue對象,那麼,我們就可以對它做很多事情。

這里直接就看幾個插件的源碼吧,看看他們是怎麼寫的,其實我也是參照了這些源碼才真正弄明白了插件是怎麼一回事。源碼很長,這里只說一些關鍵點。

針對 vue-resource 插件問題,我查看了一下 vue 的源碼,它的源碼是這樣的:

通過源碼,我們知道, Vue插件可以是一個對象或者是一個函數 。只有當插件實現了 install 介面時(有 install 這個函數時),才會調用插件的 install 方法;否則再判斷插件本身是否是一個函數,如果是,就直接調用它。

現在就能很好的解釋 vue-resource 插件的寫法了。好吧,我也是剛剛得知,又長了一點見識。

其實官網也有 說明 :

寫一篇文章,對別人來說是一種分享,其實對自己來說更是一種提高。因為你要寫好一篇文章,一方面你得盡量保證其正確性,有時候你不得不親自去驗證,另一方面也是對自己所學的知識進行一遍系統的復習和整理。

如果你有時間,我建議你多寫一些技術類文章;如果你實在沒時間寫,那也要多讀讀別人寫的文章。

『叄』 這種VUE代碼 是怎麼寫的

應該是打包工具自動生成的吧。
像這種代碼類似庫源碼,是挺難閱讀的。

『肆』 vue生命周期詳解

vue源碼中最終執行生命周期函數都是調用 callHook 方法, callHook 函數的邏輯很簡單,根據傳入的生命周期類型 hook ,去拿到 vm.$options[hook] 對應的回調函數數組,然後遍歷執行,執行的時候把 vm 作為函數執行的上下文。

1. new Vue(options) :創建一個vm實例;

2. mergeOptions(resolveConstructorOptions(vm.constructor), options, vm) :合並Vue構造函數里options和傳入的options或合並父子的options。比如:在mergeOptions函數中會調用mergeHook方法合並生命周期的鉤子函數,mergeHook方法原理是只有父時返回父,只有子時返回數組類型的子。父、子都存在時,將子添加在父的後面返回組合而成的數組。這也是父子均有鉤子函數的時候,先執行父的後執行子的的原因;

3. initLifecycle(vm)、initEvents(vm)、initRender(vm) :在創建的vm實例上初始化生命周期、事件、渲染相關的屬性;

4. callHook(vm, 'beforeCreate') :調用beforeCreate生命周期鉤子函數;

5. initInjections(vm)、initState(vm)、initProvide(vm) :初始化數據:inject、state、provide。initState 的作用是初始化 props、data、methods、watch、computed 等屬性;

6. callHook(vm, 'created') :調用created生命周期鉤子函數;

7. vm.$mount(vm.$options.el) : $mount 方法在多個文件中都有定義,如"src/platform/web/entry-runtime-with-compiler.js"、"src/platform/web/runtime/index.js"、"src/platform/weex/runtime/index.js"。因為 $mount 方法的實現是和平台、構建方式相關的。以"entry-runtime-with-compiler.js"為例,關鍵步驟是查看 vm.$options 中是否有render方法,如果沒有則會根據el和template屬性確定最終的template字元串,再調用 compileToFunctions 方法將template字元串轉為render方法,最後,調用原先原型上的$mount方法,即開始執行"lifecycle.js"中 mountComponent 方法;

8. callHook(vm, 'beforeMount') :調用beforeMount生命周期鉤子函數;

9. vm._render() => vm._update() => vm.__patch__() :先執行vm._render方法,即調用createElement生成虛擬DOM,即VNode ,每個VNode有children ,children 每個元素也是⼀個 VNode,這樣就形成了⼀個 VNode Tree;再調用vm._update方法進行首次渲染,vm._update方法核心是調用vm. patch 方法,這個方法跟vm.$mount一樣跟平台相關;vm. patch 方法則是根據生成的VNode Tree遞歸createElm方法創建真實Dom Tree掛載到Dom上;

10. callHook(vm, 'mount') :調用mount生命周期鉤子函數:VNode patch 到 Dom 之後會執行 'invokeInsertHook'函數,把 insertedVnodeQueue 中保存的mount鉤子函數執行一遍,insertedVnodeQueue隊列中的鉤子函數是在根據VNode Tree遞歸createElm方法創建真實Dom Tree過程生成的鉤子函數順序隊列,因此mounted鉤子函數的執行順序是先子後父;

11. data changes :數據更新,nextTick中執行 flushSchelerQueue 方法,該方法會執行watcher隊列中的watcher;

12. callHook(vm, 'beforeUpdate') :執行watcher時會執行watcher的before方法,即調用beforeUpdate生命周期鉤子函數;

13. Virtual DOM re-render and patch :重新render生成新的Virtual DOM,並且patch到DOM上;

14. callHook(vm, 'updated') :調用updated生命周期鉤子函數;

15. vm.$destroy() :啟動卸銷毀過程;

16. callHook(vm, 'beforeDestroy') :調用beforeDestroy生命周期鉤子函數;

17. Teardown watchers, childcomponents and event listeners :執行一系列銷毀動作,在 $destroy 的執行過程中,它又會執行 vm.__patch__(vm._vnode, null) 觸發它子組件的銷毀鉤子函數,這樣一層層的遞歸調用,所以 destroyed 鉤子函數執行順序是先子後父,和 mounted 過程一樣。

18. callHook(vm, 'destroyed ') :調用destroyed 生命周期鉤子函數。

『伍』 web前端開發培訓去哪好

很多人對前端開發工程師的崗位比較感興趣但是卻不清楚該怎麼下手,這是大多數人都會想到去前端培訓班進行學習。這主要是因為前端培訓符合更多人的需求,大家都想要系統的學好前端開發技術,並且在最快的時間能夠掌握這些技術知識,並且找到相對應的工作。那麼,這樣一來培訓班就成為了大家最好的選擇。
如果你想要快速入行找到一家比較好的前端開發培訓機構,個人覺得大家可以通過下邊這幾個步驟進行。
第一步、首先,去了解一下這些前端培訓機構的口碑怎麼樣,通過口碑我們可以初步的篩選出一些不錯的機構,畢竟口碑也是需要得到廣大學員的認可,並通過長時間的積累才能夠達到的,參考價值還是比較高的。
第二步、就是去了解每一個機構的師資、課程內容、學習環境以及就業服務等多方面和學習就業有直接關系的內容,從而保障大家在培訓學習過程中的教學質量,讓自己能夠在學習結束後獲得更多的知識。
第三步、就是進行實地考察,我們在網路上或者是很朋友哪裡得到的情況,很多的時候還是會存在應的差別。因為培訓機構也並不是一層不變的,有些機構可能之前確實比較好,但經過多年的發展也可能變差,所以想要了解真實的情況,還是免不了要自己去實地進行考察一番,這樣對於自己的選擇更有益處。

『陸』 【面試題解析】從 Vue 源碼分析 key 的作用

最近看了面試題中有一個這樣的題, v-for 為什麼要綁定 key?

Vue 中 key 很多人都弄不清楚有什麼作用,甚至還有些人認為不綁定 key 就會報錯。

其實沒綁定 key 的話,Vue 還是可以正常運行的,報警告是因為沒通過 Eslint 的檢查。

接下來將通過源碼一步步分析這個 key 的作用。

Virtual DOM 最主要保留了 DOM 元素的層級關系和一些基本屬性,本質上就是一個 JS 對象。相對於真實的 DOM,Virtual DOM 更簡單,操作起來速度更快。

如果需要改變 DOM,則會通過新舊 Virtual DOM 對比,找出需要修改的節點進行真實的 DOM 操作,從而減小性能消耗。

傳統的 Diff 演算法需要遍歷一個樹的每個節點,與另一棵樹的每個節點對比,時間復雜度為 O(n²)。

Vue 採用的 Diff 演算法則通過逐級對比,大大降低了復雜性,時間復雜度為 O(n)。

VNode 更新首先會經過 patch 函數, patch 函數源碼如下:

vnode 表示更新後的節點,oldVnode 表示更新前的節點,通過對比新舊節點進行操作。

1、vnode 未定義,oldVnode 存在則觸發 destroy 的鉤子函數

2、oldVnode 未定義,則根據 vnode 創建新的元素

3、oldVnode 不為真實元素並且 oldVnode 與 vnode 為同一節點,則會調用 patchVnode 觸發更新

4、oldVnode 為真實元素或者 oldVnode 與 vnode 不是同一節點,另做處理

接下來會進入 patchVnode 函數,源碼如下:

1、vnode 的 text 不存在,則會比對 oldVnode 與 vnode 的 children 節點進行更新操作

2、vnode 的 text 存在,則會修改 DOM 節點的 text

接下來在 updateChildren 函數內就可以看到 key 的用處。

key 的作用主要是給 VNode 添加唯一標識,通過這個 key,可以更快找到新舊 VNode 的變化,從而進一步操作。

key 的作用主要表現在以下這段源碼中。

updateChildren 過程為:

1、分別用兩個指針(startIndex, endIndex)表示 oldCh 和 newCh 的頭尾節點

2、對指針所對應的節點做一個兩兩比較,判斷是否屬於同一節點

3、如果4種比較都沒有匹配,那麼判斷是否有 key,有 key 就會用 key 去做一個比較;無 key 則會通過遍歷的形式進行比較

4、比較的過程中,指針往中間靠,當有一個 startIndex > endIndex,則表示有一個已經遍歷完了,比較結束

從 VNode 的渲染過程可以得知,Vue 的 Diff 演算法先進行的是同級比較,然後再比較子節點。

子節點比較會通過 startIndex、endIndex 兩個指針進行兩兩比較,再通過 key 比對子節點。如果沒設置 key,則會通過遍歷的方式匹配節點,增加性能消耗。

所以不綁定 key 並不會有問題,綁定 key 之後在性能上有一定的提升。

綜上,key 主要是應用在 Diff 演算法中,作用是為了更快速定位出相同的新舊節點,盡量減少 DOM 的創建和銷毀的操作。

希望以上內容能夠對各位小夥伴有所幫助,祝大家面試順利。

Vue 的文檔中對 key 的說明如下:

關於就地修改,關鍵在於 sameVnode 的實現,源碼如下:

可以看出,當 key 未綁定時,主要通過元素的標簽等進行判斷,在 updateChildren 內會將 oldStartVnode 與 newStartVnode 判斷為同一節點。

如果 VNode 中只包含了文本節點,在 patchVnode 中可以直接替換文本節點,而不需要移動節點的位置,確實在不綁定 key 的情況下效率要高一丟丟。

某些情況下不綁定 key 的效率更高,那為什麼大部分Eslint的規則還是要求綁定 key 呢?

因為在實際項目中,大多數情況下 v-for 的節點內並不只有文本節點,那麼 VNode 的位元組點就要進行銷毀和創建的操作。

相比替換文本帶來的一丟丟提升,這部分會消耗更多的性能,得不償失。

了解了就地修改,那麼我們在一些簡單節點上可以選擇不綁定 key,從而提高性能。

如果你喜歡我的文章,希望可以關注一下我的公眾號【前端develop】

熱點內容
app什麼情況下找不到伺服器 發布:2025-05-12 15:46:25 瀏覽:711
php跳過if 發布:2025-05-12 15:34:29 瀏覽:465
不定時演算法 發布:2025-05-12 15:30:16 瀏覽:129
c語言延時1ms程序 發布:2025-05-12 15:01:30 瀏覽:163
動物園靈長類動物配置什麼植物 發布:2025-05-12 14:49:59 瀏覽:732
wifi密碼設置什麼好 發布:2025-05-12 14:49:17 瀏覽:147
三位數乘兩位數速演算法 發布:2025-05-12 13:05:48 瀏覽:395
暴風影音緩存在哪裡 發布:2025-05-12 12:42:03 瀏覽:539
access資料庫exe 發布:2025-05-12 12:39:04 瀏覽:627
五開的配置是什麼 發布:2025-05-12 12:36:37 瀏覽:363