国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

Vue渲染過(guò)程淺析

2019-11-19 11:59:44
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

Vue 推薦在絕大多數(shù)情況下使用 template 來(lái)創(chuàng)建你的 HTML。但是模板畢竟是模板,不是真實(shí)的dom節(jié)點(diǎn)。從模板到真實(shí)dom節(jié)點(diǎn)還需要經(jīng)過(guò)一些步驟

  1. 把模板編譯為render函數(shù)
  2. 實(shí)例進(jìn)行掛載, 根據(jù)根節(jié)點(diǎn)render函數(shù)的調(diào)用,遞歸的生成虛擬dom
  3. 對(duì)比虛擬dom,渲染到真實(shí)dom
  4. 組件內(nèi)部data發(fā)生變化,組件和子組件引用data作為props重新調(diào)用render函數(shù),生成虛擬dom, 返回到步驟3

第一步: 模板到render

在我們使用Vue的組件化進(jìn)行開(kāi)發(fā)應(yīng)用的時(shí)候, 如果仔細(xì)的查看我們要引入的組件, 例子如下

// 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這個(gè)模塊,里面是一個(gè)對(duì)象,對(duì)象里面存在一個(gè)方法叫做render。在說(shuō)render函數(shù)之前,我們可以想一想,每一次加載一個(gè)組件,然后對(duì)模板進(jìn)行解析,解析完后,生成Dom,掛載到頁(yè)面上。這樣會(huì)導(dǎo)致效率很低效。而使用Vue-cli進(jìn)行組件化開(kāi)發(fā),在我們引入組件的后,其實(shí)會(huì)有一個(gè)解析器(vue-loader)對(duì)此模板進(jìn)行了解析,生成了render函數(shù)。當(dāng)然,如果沒(méi)有通過(guò)解析器解析為render函數(shù),也沒(méi)有關(guān)系,在組件第一次掛載的時(shí)候,Vue會(huì)自己進(jìn)行解析。源碼請(qǐng)參考: https://github.com/vuejs/vue/blob/dev/src/platforms/web/entry-runtime-with-compiler.js

這樣,能保證組件每次調(diào)用的都是render函數(shù),使用render函數(shù)生成VNode。

第二步:虛擬節(jié)點(diǎn)VNode

我們把Vue的實(shí)例掛載到#app, 會(huì)調(diào)用實(shí)例里面的render方法,生成虛擬DOM。來(lái)看看什么是虛擬節(jié)點(diǎn),把例子修改一下。

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

上面生成的VNode就是虛擬節(jié)點(diǎn),虛擬節(jié)點(diǎn)里面有一個(gè)屬性elm, 這個(gè)屬性指向真實(shí)的DOM節(jié)點(diǎn)。因?yàn)閂Node指向了真實(shí)的DOM節(jié)點(diǎn),那么虛擬節(jié)點(diǎn)經(jīng)過(guò)對(duì)比后,生成的DOM節(jié)點(diǎn)就可以直接進(jìn)行替換。

這樣有什么好處呢?

一個(gè)組件對(duì)象,如果內(nèi)部的data發(fā)生變化,觸發(fā)了render函數(shù),重新生成了VNode節(jié)點(diǎn)。那么就可以直接找到所對(duì)應(yīng)的節(jié)點(diǎn),然后直接替換。那么這個(gè)過(guò)程只會(huì)在本組件內(nèi)發(fā)生,不會(huì)影響其他的組件。于是組件與組件是隔離的。
例子如下:

// main.jsconst root = new Vue({ data: {  state: true }, mounted() {  setTimeout(() => {   console.log(this)   this.state = false  }, 1000) }, render: function(h) {  const { state } = this // state 變化重新觸發(fā)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>


我們可以看到,當(dāng)main.js中重新觸發(fā)render函數(shù)的時(shí)候,render方法里面有引用App.vue這個(gè)子組件。但是并沒(méi)有觸發(fā)App.vue組件的的render函數(shù)。

在一個(gè)組件內(nèi),什么情況會(huì)觸發(fā)render?

如何才能觸發(fā)組件的render

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

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

當(dāng)props會(huì)觸發(fā)組件的重新渲染是怎么發(fā)生的呢?

把父組件的data通過(guò)props傳遞給子組件的時(shí)候,子組件在初次渲染的時(shí)候生命周期或者render方法,有調(diào)用data相關(guān)的props的屬性, 這樣子組件也被添加到父組件的data的相關(guān)屬性依賴(lài)中,這樣父組件的data在set的時(shí)候,就相當(dāng)于觸發(fā)自身和子組件的update。

例子如下:

// main.vueimport 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 變化重新觸發(fā)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 狀態(tài)發(fā)生了變化,由false => true, 觸發(fā)了自身與子組件的render方法。

補(bǔ)充

上面的內(nèi)容是本人的一些使用心得,由于水平有限, 內(nèi)容有些錯(cuò)誤或者表達(dá)不當(dāng)。多歡迎大神來(lái)指導(dǎo)!!!

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

這是由于瀏覽器的渲染機(jī)制導(dǎo)致的,瀏覽器是從頭到尾  如果你的js引用在底部,那么瀏覽器會(huì)先加載dom此時(shí),你用于渲染的{{}}識(shí)別符,因?yàn)檫€沒(méi)讀到該識(shí)別符對(duì)應(yīng)的js文件,所以會(huì)被解析為字符串而顯示在頁(yè)面中,我們可以用過(guò)自定義屬性v-cloak解決,

實(shí)例對(duì)象對(duì)應(yīng)標(biāo)簽中加入 v-cloak:

<div id="wrap" v-cloak>

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

  [v-cloak]{  display:none}

vue實(shí)例創(chuàng)建完成后會(huì)把v-cloak去掉,在沒(méi)創(chuàng)建實(shí)例對(duì)象時(shí),該標(biāo)簽內(nèi)的內(nèi)容都會(huì)被隱藏

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 梁平县| 金塔县| 清苑县| 乌鲁木齐市| 政和县| 洪雅县| 石泉县| 馆陶县| 砀山县| 枣阳市| 东兰县| 新河县| 炎陵县| 麟游县| 丰都县| 永康市| 白沙| 延吉市| 平昌县| 北辰区| 沅江市| 临邑县| 柘城县| 南涧| 本溪市| 松潘县| 云浮市| 荥经县| 博湖县| 哈巴河县| 孙吴县| 德兴市| 巩留县| 尼勒克县| 烟台市| 通州区| 铅山县| 大余县| 长沙县| 乐陵市| 当阳市|