国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - vue.js - 淺談vue首次渲染全過程

淺談vue首次渲染全過程

2022-03-07 15:47ら陳佚晨 vue.js

這篇文章主要介紹了淺談vue首次渲染全過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

昨天有朋友問我vue在頁面第一次加載時到底做了些什么,看來這個問題在很多朋友心中可能還比較模糊,今天我們一起來詳細的看看vue的首次渲染過程

了解vue首次渲染全過程,我們應該從哪說起呢,很明顯,是不是應該從入口文件說起啊,即main.js

1、vue初始化

首先,我們看main.js中,第一個最關鍵的肯定是引入vue吧

import vue from "vue"

其實,vue被打包后,dist文件夾中存在多個版本,分別是
通用版本(UMD):中的完整版 vue.js 和運行時版本 vue.runtime.js
CommonJs版本:中的完整版vue.common.js 和 運行時版本vue.runtime.common.js
ES Module版本:中的完整版vue.esm.js 和 運行時版本vue.runtime.esm.js
一般在vue2.6以后,我們用vue/cli創建的項目用的都是vue.runtime.esm.js運行時版本
即,引入vue時會引入vue.esm.js這個版本

那么,vue引入以后,是不是vue中的相關代碼會被執行啊。那最新執行vue源碼中的哪塊代碼呢(引入的vue就是vue源碼中被打包后的vue),我們先得知道入口文件在哪

vue入口文件

vue的入口文件主要在vue源碼結構的src/platforms/web下

淺談vue首次渲染全過程

vue打包時,可以選擇不同的vue入口文件來進行打包,不同的入口文件打包出來的vue版本不同。
這里我們主要來說完整版entry-runtime-with-compiler.js
下面我們先來了解下完整版和運行時版本的區別

完整版和運行時版本的區別

完整版是運行時版本 + 編譯器的組合
運行時版本不帶編譯器compiler,即沒有模板編譯功能,主要用來創建vue實例,渲染虛擬dom。體積小,更輕量(compiler編譯器有3000多行代碼)
什么意思呢,即

<body>
	<div id="app">
		<p>我是index.html中的內容</p>
	</div>
</body>
new Vue({
	template: "<div>我是template模板渲染出來的內容</div>"
}).$mount("#app")

上面的情況,
如果是完整版vue,存在compiler編譯器,會將new Vue時傳入的template編譯成render函數,并賦值給options的render屬性,然后$mount后,會渲染render函數成虛擬dom,再將虛擬dom轉話為真實dom,所以最終頁面會出現 我是template模板渲染出來的內容 這句話。原本的那句話會被覆蓋

如果是運行時版本,沒有編譯器,不會編譯template中的內容,則頁面只會存在原來的dom

下面我們來繼續往下看
找到入口文件后,我們開始看看會執行哪些東西

淺談vue首次渲染全過程

可以看出,入口文件先導入了vue,然后經過了一些處理,最終又導出了vue
我們先通過導入vue的路徑一步一步找到vue構造函數的創建在哪創建的。如上圖,從runtime/index中導入了vue,那么我們去看runtime/index

淺談vue首次渲染全過程

這個文件也是一樣,import了vue 經過了一些處理,然后又導出了vue,我們繼續往上找,找core/index

淺談vue首次渲染全過程

這個文件也是一樣,我們繼續往上找,找./instance/index

淺談vue首次渲染全過程

在這里,我們找到了我們的vue構造函數的創建,是在源碼的src/core/instance/index.js文件中。

那么,我們從剛剛上面的引用關系,就能發現,vue被我們引入到項目中后,首先會執行的文件的順序是

src/core/instace/index.js ===> 1
src/core/index.js ===> 2
src/platforms/web/runtime/index.js ===> 3
src/platforms/web/entry-runtime-with-compiler.js 4

那么,我們再來看,每個文件都執行了些什么,
首先 src/core/instace/index.js

1.1、src/core/instace/index.js

首先,此文件定義了vue構造函數,并初始化了一些vue的實例屬性和實例方法,即,在vue.prototype原型下新增了各種方法和屬性

淺談vue首次渲染全過程

下面,我們具體來看下,每一個方法具體初始化了vue的哪些實例屬性或方法

1.1.1、initMixin(Vue)

淺談vue首次渲染全過程

1.1.2、stateMixin(Vue)

淺談vue首次渲染全過程

1.1.3、eventsMixin(Vue)

淺談vue首次渲染全過程

1.1.4、lifecycleMixin(Vue)

淺談vue首次渲染全過程

1.1.5、renderMixin(Vue)

淺談vue首次渲染全過程

src/core/instace/index.js執行完后,會繼續執行下一個文件

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  if (process.env.NODE_ENV !== "production") {
    configDef.set = () => {
      warn(
        "Do not replace the Vue.config object, set individual fields instead."
      )
    }
  }
  // 新增了一個config屬性
  Object.defineProperty(Vue, "config", configDef)

  // 新增了一個靜態成員 util
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  // 新增了3個靜態成員set  delete  nextTick
  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

  // 新增了一個靜態成員 observable
  Vue.observable = <T>(obj: T): T => {
    observe(obj)
    return obj
  }

  // 初始化了options  此時options是空對象</T>
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + "s"] = Object.create(null)
  })

  Vue.options._base = Vue

  // 注冊了一個全局組件keep-alive builtInComponents內部就是keep-alive的組件導出
  extend(Vue.options.components, builtInComponents)

  // 下面是分別初始化了Vue.use() Vue.mixin() Vue.extend() 
  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  // 初始化Vue.directive(), Vue.component(), vue.filter()
  initAssetRegisters(Vue)
}

1.2、src/core/index.js

淺談vue首次渲染全過程

可以看出,這個文件,主要是給vue新增了很多靜態實例方法和屬性,具體新增了哪些,
我們繼續看被執行的那個方法initGlobalAPI(Vue)

1.2.1 initGlobalAPI(Vue)

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  if (process.env.NODE_ENV !== "production") {
    configDef.set = () => {
      warn(
        "Do not replace the Vue.config object, set individual fields instead."
      )
    }
  }
  // 新增了一個config屬性
  Object.defineProperty(Vue, "config", configDef)

  // 新增了一個靜態成員 util
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  // 新增了3個靜態成員set  delete  nextTick
  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

  // 新增了一個靜態成員 observable
  Vue.observable = <T>(obj: T): T => {
    observe(obj)
    return obj
  }

  // 初始化了options  此時options是空對象</T>
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + "s"] = Object.create(null)
  })

  Vue.options._base = Vue

  // 注冊了一個全局組件keep-alive builtInComponents內部就是keep-alive的組件導出
  extend(Vue.options.components, builtInComponents)

  // 下面是分別初始化了Vue.use() Vue.mixin() Vue.extend() 
  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  // 初始化Vue.directive(), Vue.component(), vue.filter()
  initAssetRegisters(Vue)
}

1.3、src/platforms/web/runtime/index.js

淺談vue首次渲染全過程

1.4、src/platforms/web/entry-runtime-with-compiler.js

淺談vue首次渲染全過程

此文件,最主要的作用就重寫了vue原型下的$mount方法。具體$mount方法中做了些什么,我們后面會講

1.5、vue初始化總結

上面寫的整個過程,都是用戶在使用vue時,引入vue文件后,立刻會執行的一些東西

這些執行完后,是不是會繼續去執行我們項目中的main.js文件啊,
此時會執行到

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app")

這個時候,會開始調用,我們的vue構造函數

2、vue構造函數執行

此時,會先執行vue構造函數,

淺談vue首次渲染全過程

可以看出,主要是執行了_init方法,從這里開始,vue的生命周期開始執行了

淺談vue首次渲染全過程

上面只是_init()方法中最主要的一部分代碼,(代碼太多,我就不全部截圖了,你們自己到源碼中看)。可以看出:

2.1、beforeCreate鉤子

在生命周期beforeCreate鉤子之前,vue主要做的事情就是給vue原型新增各種屬性和方法,給vue新增各種靜態屬性和方法,以及給vm實例新增各種屬性和方法

2.2、created鉤子

上圖可以看出,beforeCreate鉤子執行結束后,主要執行了3個方法:initInjections, initState, initProvide

// 把inject注入到vm實例
callHook(vm, "beforeCreate")

// 把inject注入到vm實例
initInjections(vm)

// 初始化vm的$props,$methods,$data,computed,watch
initState(vm)

// 把provide注入vm實例
initProvide(vm)

// 執行created生命周期
callHook(vm, "created")

其實,重點是initState(vm)方法,該方法中,初始化了vm實例的$props, $data, $methods, computed, watch等。同時,在里面調用了一個initData()方法,該方法內會調用observer() 方法,將data中的數據都轉化為響應式數據。即添加數據攔截器。

所以可以看出,在created生命周期之前,vm的$props, $data, $methods, computed, watch屬性都會初始化完成,
故,這也就是為什么,我們可以在created中調用我們data中的各種數據以及調用props或者methods等下面的各種方法了。

created生命周期走完以后,繼續往下看

淺談vue首次渲染全過程

可以看出,這里判斷了vm.$options.el是否存在,vm.$options.el是什么啊。
new Vue({})時,傳入的那個對象的所有屬性,都會被掛載options下,

new Vue({
  el: "#app"
  router,
  store,
  render: h => h(App)
})

故,vm.$options.el就是上面傳入的el。
這里判斷el是否存在,如果存在,才會繼續往下執行$mount

那大家可能會好奇了,如果不存在,那是不是就卡死了,后面都不會走了。是的,如果沒有,就不會繼續走了,要想代碼繼續往下走,必然要執行$mount方法。
此時,我們再看一直vue常用的情況

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app")

這里沒有傳入el,所以源碼中的

淺談vue首次渲染全過程

肯定是不會走的。但是,用戶在new Vue的時候可以自己用new 出來的vue實例去調用$mount。這么一來,大家看我們官網的生命周期圖,可能就更容易看懂了

淺談vue首次渲染全過程

好了,下面我們繼續往下,下一步是執行 $mount,我們來看 $mount方法

2.3、$mount函數

我們之前初始化的時候,重寫過$mount還記得嗎,所以,此時我們執行$mount時,執行的是重寫后的mount

淺談vue首次渲染全過程

這里在重寫前先存儲了重寫前的mount方法,然后在最后調用了重寫前的mount方法。
重寫后,最關鍵的代碼是判斷是否有render函數

淺談vue首次渲染全過程

這一步的主要作用就是判斷是否有render函數,
如果有,直接往下執行重寫前的$mount方法前渲染render函數,

如果沒有,就會前判斷是否存在template模板(options.template是否存在,options.template可能是id選擇器,可能是dom),如果存在模板,就會獲取到模板中的內容,并賦值給template,options.template不存在,那么會直接以el指定的dom為模板(即#app),獲取到el下的dom,賦值給template

template取到dom后,然后繼續往下,將此template編譯成render函數,并將編譯出來的render函數掛載options.render屬性下

淺談vue首次渲染全過程

然后會繼續執行重寫前的$mount,理解了這,我們就能理解生命周期圖中的另一部分了

淺談vue首次渲染全過程

2.4、beforeMount

下面,我們繼續來看重寫前的$mount函數的執行

淺談vue首次渲染全過程

可以看出 $mount中主要是執行了函數mountComponent,我們繼續看mountComponent函數

淺談vue首次渲染全過程

可以看出,此函數,主要做了以下4件事
我們一件一件來看
1、執行了beforeMount鉤子,所以可以得出結論,再beforeMount之前,我們主要是初始化和得到render函數。而beforeMount之后,才是開始將render函數渲染成虛擬dom,然后更新真實dom
render函數得到的途徑有3種
第一:用戶自己傳入render

淺談vue首次渲染全過程

第二:.vue文件編譯成render

淺談vue首次渲染全過程

這種方式,就是自己傳入了一個render函數,函數內用h函數前執行了App.vue文件。
.vue文件最終轉化為render函數需要借助vue-loader來完成

第三、將template模板編譯成render函數

淺談vue首次渲染全過程
2、定義了一個updateComponent函數,此函數內調用了vm的_update方法,同時執行了vm._render()方法,并將執

行后的結果當做參數傳給_update方法。_render方法我們前面說過,他內部渲染了render函數成為虛擬dom,故_render()的返回值是一個vnode。

我們先來看下_render()函數內部如何將render函數轉化為虛擬dom的

淺談vue首次渲染全過程

然后我們再看_update函數內部做了啥

淺談vue首次渲染全過程

可以看出,_update函數中,執行了__patch__方法去對比兩個新舊dom,從而找出差異,更新真實dom。如果是首次渲染,則直接將當前的vnode,生成真實的dom。

故得出結論,整個updateComponent方法的主要作用就是渲染render函數,更新dom
而什么時候更新dom的關鍵,就在于什么時候去調用這個updateComponent函數了

3、new 了一個watcher實例

淺談vue首次渲染全過程

可以看出,new一個watcher實例的同時,傳入了updateComponent函數作為參數。
此時,我們看new Watcher時,會執行Watcher構造函數,我們看Watcher構造函數內做了啥

淺談vue首次渲染全過程

watcher分為3種,渲染watcher,$watch函數的watcher,computed的watcher。我們這里渲染頁面的是渲染watcher

上面將我們傳入的函數傳給了getter

淺談vue首次渲染全過程

繼續往下走,調用了get()

淺談vue首次渲染全過程

可以看出,get()中調用了我們傳入的函數,而我們傳入的函數就是渲染render函數,并觸發虛擬dom更新真實dom,而返回的值,就是渲染后的真實dom,最后賦值給了this.value,而this.value最后會用于更新依賴者。而我們當前這個wather實例,是主vue實例的watcher,故可以理解為整個頁面的watcher。當我們調用this.$fouceUpdate()時,就是調用這個實例的update方法,去更新整個頁面。
所以說,new Wacher的時候 updateComponent會自動調用一次,這就是我們的首次渲染。

此時,我們繼續往下看

淺談vue首次渲染全過程

這內部,還做了個判斷,如果vm._isMounted為true(即Mounted鉤子已經執行過了),而vm._isDestroyed為fase時(即當前組件還未銷毀)。此時,如果產生更新,則說明并非首次渲染,那么執行beforeUpdate鉤子,后續肯定還會走updated。這里我們就不說updated的事了

new Watcher后,代碼繼續往下走

淺談vue首次渲染全過程

判斷了當前vnode如果null,說明之前沒有生成過虛擬dom,也就說明這次肯定是首次渲染,此時,vm._isMounted置為true。并執行mounted鉤子函數,此時,首次渲染完成。

2.5、mounted

可以看出,整個beforeMount 到 mounted過程中,主要做的工作就是
1、渲染render函數成為虛擬dom vnode
2、執行vm._update函數,將虛擬dom轉化為真實dom
如果是beforeUpdate 到 updated鉤子之間,說明不是首次渲染,那么虛擬dom會有新舊兩個。此時vm._update函數的作用就是對比新舊兩個vnode,得出差異,更新需要更新的地方

首次渲染整個過程就是這樣。到此這篇關于淺談vue首次渲染全過程的文章就介紹到這了,更多相關vue首次渲染內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/weixin_42707287/article/details/115796218

延伸 · 閱讀

精彩推薦
  • vue.js詳解vue 表單綁定與組件

    詳解vue 表單綁定與組件

    這篇文章主要介紹了vue 表單綁定與組件的相關資料,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.jsVue2.x-使用防抖以及節流的示例

    Vue2.x-使用防抖以及節流的示例

    這篇文章主要介紹了Vue2.x-使用防抖以及節流的示例,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Kyara6372022-01-25
  • vue.jsVue2.x 項目性能優化之代碼優化的實現

    Vue2.x 項目性能優化之代碼優化的實現

    這篇文章主要介紹了Vue2.x 項目性能優化之代碼優化的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    優小U9632022-02-21
  • vue.jsVue中引入svg圖標的兩種方式

    Vue中引入svg圖標的兩種方式

    這篇文章主要給大家介紹了關于Vue中引入svg圖標的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的...

    十里不故夢10222021-12-31
  • vue.jsVue多選列表組件深入詳解

    Vue多選列表組件深入詳解

    這篇文章主要介紹了Vue多選列表組件深入詳解,這個是vue的基本組件,有需要的同學可以研究下...

    yukiwu6752022-01-25
  • vue.js用vite搭建vue3應用的實現方法

    用vite搭建vue3應用的實現方法

    這篇文章主要介紹了用vite搭建vue3應用的實現方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下...

    Asiter7912022-01-22
  • vue.jsVue項目中實現帶參跳轉功能

    Vue項目中實現帶參跳轉功能

    最近做了一個手機端系統,其中遇到了父頁面需要攜帶參數跳轉至子頁面的問題,現已解決,下面分享一下實現過程,感興趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看過很多人講vue的生命周期,但總是被繞的云里霧里,尤其是自學的同學,可能js的基礎也不是太牢固,聽起來更是吃力,那我就已個人之淺見,以大白話...

    CRMEB技術團隊7992021-12-22
主站蜘蛛池模板: 肌肉男gay网站 | 91精品一区二区三区久久久久久 | 久久成人a | 五月在线视频 | 亚洲第一se情网站 | 亚洲精品久 | 欧美激情视频一区二区三区在线播放 | 日韩三级电影网 | 欧美bbbxxx| 国产无套丰满白嫩对白 | 日本中文字幕一区 | 久久艹天天艹 | 久久久久99| 999精品嫩草久久久久久99 | 亚洲国产精品一区二区第一页 | 国产精品成av人在线视午夜片 | 在线中文视频 | 国色天香成人网 | 日本三级一区二区 | 日韩三级观看 | 在线视频亚洲 | 精品国产不卡一区二区三区 | 欧美成人免费 | 91国内精品久久 | 精品亚洲一区二区三区四区五区 | 久久男人免费视频 | 91精品国产九九九久久久亚洲 | 国产一区二区三区免费在线观看 | 97超碰免费 | 亚洲日本视频 | 中文字幕一区二区三区四区五区 | 色综合久久88色综合天天 | 中国一级毛片 | www.久久99 | 亚洲av毛片一区二二区三三区 | 精品第一页 | 久久久久一区二区 | 亚洲成人aaaa | 99看片| 青娱乐一区 | 91精品国产综合久久香蕉922 |