Vue渲染過程淺析

 更新時間:2019-04-17 21:43:11   作者:佚名   我要評論(0)

Vue 推薦在絕大多數情況下使用 template 來創建你的 HTML。但是模板畢竟是模板,不是真實的dom節點。從模板到真實dom節點還需要經過一些步驟

把模板編譯為

Vue 推薦在絕大多數情況下使用 template 來創建你的 HTML。但是模板畢竟是模板,不是真實的dom節點。從模板到真實dom節點還需要經過一些步驟

  1. 把模板編譯為render函數
  2. 實例進行掛載, 根據根節點render函數的調用,遞歸的生成虛擬dom
  3. 對比虛擬dom,渲染到真實dom
  4. 組件內部data發生變化,組件和子組件引用data作為props重新調用render函數,生成虛擬dom, 返回到步驟3

第一步: 模板到render

在我們使用Vue的組件化進行開發應用的時候, 如果仔細的查看我們要引入的組件, 例子如下

// App.vue 
<template>
  <div>
    hello word
  </div>
</template>

<script>

export default {
}

</script>

<style>

</style>

在我們的主入口main.js

import Vue from 'vue'
import App from './App'

console.log(App)

new Vue({
 render: h => h(App)
}).$mount('#app')

我們能夠看到在我們引入的App這個模塊,里面是一個對象,對象里面存在一個方法叫做render。在說render函數之前,我們可以想一想,每一次加載一個組件,然后對模板進行解析,解析完后,生成Dom,掛載到頁面上。這樣會導致效率很低效。而使用Vue-cli進行組件化開發,在我們引入組件的后,其實會有一個解析器(vue-loader)對此模板進行了解析,生成了render函數。當然,如果沒有通過解析器解析為render函數,也沒有關系,在組件第一次掛載的時候,Vue會自己進行解析。源碼請參考: https://github.com/vuejs/vue/blob/dev/src/platforms/web/entry-runtime-with-compiler.js

這樣,能保證組件每次調用的都是render函數,使用render函數生成VNode。

第二步:虛擬節點VNode

我們把Vue的實例掛載到#app, 會調用實例里面的render方法,生成虛擬DOM。來看看什么是虛擬節點,把例子修改一下。

new Vue({
 render: h => {
  let root = h(App)
  console.log('root:', root)
  return root
 }
}).$mount('#app')

上面生成的VNode就是虛擬節點,虛擬節點里面有一個屬性elm, 這個屬性指向真實的DOM節點。因為VNode指向了真實的DOM節點,那么虛擬節點經過對比后,生成的DOM節點就可以直接進行替換。

這樣有什么好處呢?

一個組件對象,如果內部的data發生變化,觸發了render函數,重新生成了VNode節點。那么就可以直接找到所對應的節點,然后直接替換。那么這個過程只會在本組件內發生,不會影響其他的組件。于是組件與組件是隔離的。
例子如下:

// main.js
const root = new Vue({
 data: {
  state: true
 },
 mounted() {
  setTimeout(() => {
   console.log(this)
   this.state = false
  }, 1000)
 },
 render: function(h) {
  const { state } = this // state 變化重新觸發render
  let root = h(App)
  console.log('root:', root)
  return root
 }
}).$mount('#app')
// App.vue
<script>
export default {
 render: (h) => {
  let app = h('h1', ['hello world'])
  console.log('app:', app)
  return app
 }
}
</script>


我們可以看到,當main.js中重新觸發render函數的時候,render方法里面有引用App.vue這個子組件。但是并沒有觸發App.vue組件的的render函數。

在一個組件內,什么情況會觸發render?

如何才能觸發組件的render

數據劫持是Vue的一大特色,原理官方已經講的很多了深入響應式原理。在我們給組件的data的屬性進行的賦值的時候(set),此屬性如果在組件內部初次渲染過程被引用(data的屬性被訪問,也就是數據劫持的get), 包括生命周期方法或者render方法。于是會觸發組件的update(beforeUpdate -> render -> updated)。

注: 為了防止data被多次set從而觸發多次update, Vue把update存放到異步隊列中。這樣就能保證多次data的set只會觸發一次update。

當props會觸發組件的重新渲染是怎么發生的呢?

把父組件的data通過props傳遞給子組件的時候,子組件在初次渲染的時候生命周期或者render方法,有調用data相關的props的屬性, 這樣子組件也被添加到父組件的data的相關屬性依賴中,這樣父組件的data在set的時候,就相當于觸發自身和子組件的update。

例子如下:

// main.vue
import Vue from 'vue'
import App from './App'

const root = new Vue({
 data: {
  state: false
 },
 mounted() {
  setTimeout(() => {
   this.state = true
  }, 1000)
 },
 render: function(h) {
  const { state } = this // state 變化重新觸發render
  let root = h(App, { props: { status: state } })
  console.log('root:', root)
  return root
 }
}).$mount('#app')

window.root = root
// App.vue
<script>
export default {
 props: {
  status: Boolean
 },
 render: function (h){
  const { status } = this
  let app = h('h1', ['hello world'])
  console.log('app:', app)
  return app
 }
}
</script>

截圖如下:


main.js中 state 狀態發生了變化,由false => true, 觸發了自身與子組件的render方法。

補充

上面的內容是本人的一些使用心得,由于水平有限, 內容有些錯誤或者表達不當。多歡迎大神來指導!!!

PS:vue渲染過程的{{xxx}}顯示的解決辦法

這是由于瀏覽器的渲染機制導致的,瀏覽器是從頭到尾  如果你的js引用在底部,那么瀏覽器會先加載dom此時,你用于渲染的{{}}識別符,因為還沒讀到該識別符對應的js文件,所以會被解析為字符串而顯示在頁面中,我們可以用過自定義屬性v-cloak解決,

實例對象對應標簽中加入 v-cloak:

<div id="wrap" v-cloak>

然后在css中給定義屬性選擇器 

  [v-cloak]{

  display:none

}

vue實例創建完成后會把v-cloak去掉,在沒創建實例對象時,該標簽內的內容都會被隱藏

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:

  • 詳解vue服務端渲染(SSR)初探
  • 詳解vue渲染從后臺獲取的json數據
  • 詳解基于 Nuxt 的 Vue.js 服務端渲染實踐
  • VUEJS實戰之構建基礎并渲染出列表(1)
  • 基于vue-ssr服務端渲染入門詳解
  • 深入理解Vue 的條件渲染和列表渲染
  • 詳解Vue基于 Nuxt.js 實現服務端渲染(SSR)

相關文章

  • JSP狀態管理的簡單介紹

    JSP狀態管理的簡單介紹

    JSP狀態管理的簡單介紹 一 http協議的無狀態性 無狀態性是指:當瀏覽器發送請求給服務器時,服務器響應客戶端請求。 但是當同一個瀏覽器再次發送請求給
    2019-04-17
  • Spring獲取ApplicationContext對象工具類的實現方法

    Spring獲取ApplicationContext對象工具類的實現方法

    Spring獲取ApplicationContext對象工具類的實現方法 (1)實現的工具類: package com.util; import org.springframework.context.ApplicationConte
    2019-04-17
  • Vue渲染過程淺析

    Vue渲染過程淺析

    Vue 推薦在絕大多數情況下使用 template 來創建你的 HTML。但是模板畢竟是模板,不是真實的dom節點。從模板到真實dom節點還需要經過一些步驟 把模板編譯為
    2019-04-17
  • 使用webpack搭建vue項目實現腳手架功能

    使用webpack搭建vue項目實現腳手架功能

    本文基于node.js開發環境,安裝完node之后新建項目,通過webpack配置,實現vue-cli腳手架功能 對于剛剛接觸編程的人來說,最難的可能并不是學習一種新語法或者
    2019-04-17
  • JavaScript+Regex 身份證號碼的正則表達式及驗證詳解

    JavaScript+Regex 身份證號碼的正則表達式及驗證詳解

    簡言 在做用戶實名驗證時,常會用到身份證號碼的正則表達式及校驗方案。本文列舉了兩種驗證方案,大家可以根據自己的項目實際情況,選擇適合的方案。 身份證
    2019-04-17
  • 淺談PHP進程管理

    淺談PHP進程管理

    這篇文章是對之前一篇文章的補充和改進, 創建一個主(master)進程,主進程安裝定時器,每隔5分鐘檢測一次隊列長度,根據隊列長度計算需要的worker進程, 然后創
    2019-04-17
  • DotNetCore深入了解之HttpClientFactory類詳解

    DotNetCore深入了解之HttpClientFactory類詳解

    當需要向某特定URL地址發送HTTP請求并得到相應響應時,通常會用到HttpClient類。該類包含了眾多有用的方法,可以滿足絕大多數的需求。但是如果對其使用不當時
    2019-04-17
  • 詳解linux正則表達式(基礎正則表達式+擴展正則表達式)

    詳解linux正則表達式(基礎正則表達式+擴展正則表達式)

    正則表達式應用非常廣泛,例如:php,Python,java等,但在linux中最常用的正則表達式的命令就是grep(egrep),sed,awk等,換句話 說linux三劍客要想能工作的
    2019-04-17
  • SpringMail使用過程中的報錯解決辦法

    SpringMail使用過程中的報錯解決辦法

    SpringMail使用過程中的報錯解決辦法 1、Unable to locate provider for protocol: smtp –>缺少依賴造成的 <dependency> <groupId>javax.mail</groupI
    2019-04-17
  • 小程序自定義單頁面、全局導航欄的實現代碼

    小程序自定義單頁面、全局導航欄的實現代碼

    需求 產品說小程序返回到首頁不太方便,想添加返回首頁按鈕,UI說導航欄能不能設置背景圖片,因為那樣設計挺好看的。 需求分析并制定方案 這產品和UI都提需求
    2019-04-17

最新評論

买宝宝用品赚钱吗 股票指数 公式 黑龙江体彩6 1开奖号码 四川金七乐彩开奖走势图 体彩福建31选7的中奖规则 免费股票推荐软件 新疆11选5平台 pk10免费手机版苹果 青海快3走势图 白姐透特一肖 北京11选5现场开奖哪个软件 加拿大快乐8开奖结果怎么查 宁夏11选五平台 龙江福彩22选5走势图 上证指数吧东方财富网手机版 浙江体彩20选5开奖官方同步 江西11选5一定牛走势图