精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

面試官:只知道v-model是modelValue語(yǔ)法糖,那你可以走了

開(kāi)發(fā) 前端
將v-model指令轉(zhuǎn)換為modelValue屬性和@update:modelValue事件這一過(guò)程是在編譯時(shí)還是運(yùn)行時(shí)進(jìn)行的呢?從上面的問(wèn)題答案中我們可以知道將v-model指令轉(zhuǎn)換為modelValue屬性和@update:modelValue事件這一過(guò)程是在編譯時(shí)進(jìn)行的。

大家好,我是歐陽(yáng)!

前言

我們每天都在用v-model,并且大家都知道在vue3中v-model是:modelValue和@update:modelValue的語(yǔ)法糖。那你知道v-model指令是如何變成組件上的modelValue屬性和@update:modelValue事件呢?將v-model指令轉(zhuǎn)換為modelValue屬性和@update:modelValue事件這一過(guò)程是在編譯時(shí)還是運(yùn)行時(shí)進(jìn)行的呢?

先說(shuō)結(jié)論

下面這個(gè)是我畫(huà)的處理v-model指令的完整流程圖:

圖片圖片

首先會(huì)調(diào)用parse函數(shù)將template模塊中的代碼轉(zhuǎn)換為AST抽象語(yǔ)法樹(shù),此時(shí)使用v-model的node節(jié)點(diǎn)的props屬性中還是v-model。接著會(huì)調(diào)用transform函數(shù),經(jīng)過(guò)transform函數(shù)處理后在node節(jié)點(diǎn)中多了一個(gè)codegenNode屬性。在codegenNode屬性中我們看到?jīng)]有v-model指令,取而代之的是modelValue和onUpdate:modelValue屬性。經(jīng)過(guò)transform函數(shù)處理后已經(jīng)將v-model指令編譯為modelValue和onUpdate:modelValue屬性,此時(shí)還是AST抽象語(yǔ)法樹(shù)。所以接下來(lái)就是調(diào)用generate函數(shù)將AST抽象語(yǔ)法樹(shù)轉(zhuǎn)換為render函數(shù),到此為止編譯時(shí)做的事情已經(jīng)做完了,經(jīng)過(guò)編譯時(shí)的處理v-model指令已經(jīng)變成了modelValue和onUpdate:modelValue屬性。

接著就是運(yùn)行時(shí)階段,在瀏覽器中執(zhí)行render函數(shù)生成虛擬DOM。在生成虛擬DOM的過(guò)程中由于props屬性中有modelValue和onUpdate:modelValue屬性,所以就會(huì)給組件對(duì)象加上modelValue屬性和@update:modelValue事件。最后就是調(diào)用mount方法將虛擬DOM轉(zhuǎn)換為真實(shí)DOM。所以v-model指令轉(zhuǎn)換為modelValue屬性和@update:modelValue事件這一過(guò)程是在編譯時(shí)進(jìn)行的。

什么是編譯時(shí)?什么是運(yùn)行時(shí)?

vue是一個(gè)編譯時(shí)+運(yùn)行時(shí)一起工作的框架,之前有小伙伴私信我說(shuō)自己傻傻分不清楚在vue中什么時(shí)候是編譯時(shí),什么時(shí)候是運(yùn)行時(shí)。要回答小伙伴的這個(gè)問(wèn)題我們要從一個(gè)vue文件是如何渲染到瀏覽器窗口中說(shuō)起。

我們的vue代碼一般都是寫(xiě)在后綴名為vue的文件上,顯然瀏覽器是不認(rèn)識(shí)vue文件的,瀏覽器只認(rèn)識(shí)html、css、jss等文件類型。所以第一步就是通過(guò)webpack或者vite將一個(gè)vue文件編譯為一個(gè)包含render函數(shù)的js文件,在這一步中代碼的執(zhí)行環(huán)境是在nodejs中進(jìn)行,也就是我們所說(shuō)的編譯時(shí)。相比瀏覽器端來(lái)說(shuō)能夠拿到的權(quán)限更多,也能做更多的事情。后面就是執(zhí)行render函數(shù)生成虛擬DOM,再調(diào)用瀏覽器的DOM API根據(jù)虛擬DOM生成真實(shí)DOM掛載到瀏覽器上。在第一步后面的這些過(guò)程中代碼執(zhí)行環(huán)境都是在瀏覽器中,也就是我們所說(shuō)的運(yùn)行時(shí)。在客戶端渲染的場(chǎng)景下,一句話總結(jié)就是:代碼跑在nodejs端的時(shí)候就是編譯時(shí),代碼跑在瀏覽器端的時(shí)候就是運(yùn)行時(shí)。

圖片圖片

舉個(gè)例子

我們來(lái)看一個(gè)v-model的例子,父組件index.vue的代碼如下:

<template>
  <CommonChild v-model="inputValue" />
  <p>input value is: {{ inputValue }}</p>
</template>

<script setup lang="ts">
import { ref } from "vue";
import CommonChild from "./child.vue";

const inputValue = ref();
</script>

我們上面是一個(gè)很簡(jiǎn)單的v-model的例子,在CommonChild子組件上使用v-model綁定一個(gè)叫inputValue的ref變量,然后將這個(gè)inputValue變量渲染到p標(biāo)簽上面。

前面我們已經(jīng)講過(guò)了客戶端渲染的場(chǎng)景下,在nodejs端工作的時(shí)候是編譯時(shí),在瀏覽器端工作的時(shí)候是運(yùn)行時(shí)。那我們現(xiàn)在先來(lái)看看經(jīng)過(guò)編譯時(shí)階段處理后,剛剛進(jìn)入到瀏覽器端運(yùn)行時(shí)階段的js代碼是什么樣的。我們要如何在瀏覽器中找到這個(gè)js文件呢?其實(shí)很簡(jiǎn)單直接在network上面找到你的那個(gè)vue文件就行了,比如我這里的文件是index.vue,那我只需要在network上面找叫index.vue的文件就行了。但是需要注意一下network上面有兩個(gè)index.vue的js請(qǐng)求,分別是template模塊+script模塊編譯后的js文件,和style模塊編譯后的js文件。

那怎么區(qū)分這兩個(gè)index.vue文件呢?很簡(jiǎn)單,通過(guò)query就可以區(qū)分。由style模塊編譯后的js文件的URL中有type=style的query,如下圖所示:

圖片圖片

這時(shí)有的小伙伴就開(kāi)始疑惑了不是說(shuō)好的瀏覽器不認(rèn)識(shí)vue文件嗎?怎么這里的文件名稱是index.vue而不是index.js呢?其實(shí)很簡(jiǎn)單,在開(kāi)發(fā)環(huán)境時(shí)index.vue文件是在App.vue文件中import導(dǎo)入的,而App.vue文件是在main.js文件中import導(dǎo)入的。所以當(dāng)瀏覽器中執(zhí)行main.js的代碼時(shí)發(fā)現(xiàn)import導(dǎo)入了App.vue文件,那瀏覽器就會(huì)去加載App.vue文件。當(dāng)瀏覽器加載完App.vue文件后執(zhí)行時(shí)發(fā)現(xiàn)import導(dǎo)入了index.vue文件,所以瀏覽器就會(huì)去加載index.vue文件,而不是index.js文件。

至于什么時(shí)候?qū)ndex.vue文件中的template模塊、script模塊、style模塊編譯成js代碼,我們?cè)?nbsp;通過(guò)debug搞清楚.vue文件怎么變成.js文件文章中已經(jīng)講過(guò)了當(dāng)import加載一個(gè)文件時(shí)會(huì)觸發(fā)@vitejs/plugin-vue包中的transform鉤子函數(shù),在這個(gè)transform鉤子函數(shù)中會(huì)將template模塊、script模塊、style模塊編譯成js代碼。所以在瀏覽器中拿到的index.vue文件就是經(jīng)過(guò)編譯后的js代碼了。

現(xiàn)在我們?cè)跒g覽器的network中來(lái)看剛剛進(jìn)入編譯時(shí)index.vue文件代碼,簡(jiǎn)化后的代碼如下:

import {
  Fragment as _Fragment,
  createElementBlock as _createElementBlock,
  createElementVNode as _createElementVNode,
  createVNode as _createVNode,
  defineComponent as _defineComponent,
  openBlock as _openBlock,
  toDisplayString as _toDisplayString,
  ref,
} from "/node_modules/.vite/deps/vue.js?v=23bfe016";
import CommonChild from "/src/components/vModel/child.vue?t=1710943659056";
import "/src/components/vModel/index.vue?vue&type=style&index=0&scoped=0ebe7d62&lang.css";

const _sfc_main = _defineComponent({
  __name: "index",
  setup(__props, { expose: __expose }) {
    __expose();
    const inputValue = ref();
    const __returned__ = { inputValue, CommonChild };
    return __returned__;
  },
});

function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  return (
    _openBlock(),
    _createElementBlock(
      _Fragment,
      null,
      [
        _createVNode(
          $setup["CommonChild"],
          {
            modelValue: $setup.inputValue,
            "onUpdate:modelValue":
              _cache[0] ||
              (_cache[0] = ($event) => ($setup.inputValue = $event)),
          },
          null,
          8,
          ["modelValue"]
        ),
        _createElementVNode(
          "p",
          null,
          "input value is: " + _toDisplayString($setup.inputValue),
          1
          /* TEXT */
        ),
      ],
      64
      /* STABLE_FRAGMENT */
    )
  );
}

_sfc_main.render = _sfc_render;
export default _sfc_main;

從上面的代碼中我們可以看到編譯后的js代碼主要分為兩塊,第一塊是_sfc_main組件對(duì)象,里面有name屬性和setup方法。一個(gè)vue組件在運(yùn)行時(shí)實(shí)際就是一個(gè)對(duì)象,這里的_sfc_main就是一個(gè)vue組件對(duì)象。至于defineComponent函數(shù)的作用是在定義 Vue 組件時(shí)提供類型推導(dǎo)的輔助函數(shù),所以在我們這個(gè)場(chǎng)景沒(méi)什么用。我們接著來(lái)看第二塊_sfc_render,從名字我想你應(yīng)該已經(jīng)猜到了他是一個(gè)render函數(shù)。執(zhí)行這個(gè)_sfc_render函數(shù)就會(huì)生成虛擬DOM,然后再由虛擬DOM生成瀏覽器上面的真實(shí)DOM。

我們?cè)賮?lái)看這個(gè)render函數(shù),在這個(gè)render函數(shù)前面會(huì)調(diào)用openBlock函數(shù)和createElementBlock函數(shù)。他的作用是在編譯時(shí)盡可能的提取多的關(guān)鍵信息,可以減少運(yùn)行時(shí)比較新舊虛擬DOM帶來(lái)的性能開(kāi)銷,我們這篇文章不關(guān)注這點(diǎn),所以我們接下來(lái)會(huì)直接看下面的_createVNode函數(shù)和_createElementVNode函數(shù)。

v-model語(yǔ)法糖怎么工作的

我們接著來(lái)看render函數(shù)中的_createVNode函數(shù)和_createElementVNode函數(shù),代碼如下:

import {
  createElementVNode as _createElementVNode,
  createVNode as _createVNode,
} from "/node_modules/.vite/deps/vue.js?v=23bfe016";

_createVNode(
  $setup["CommonChild"],
  {
    modelValue: $setup.inputValue,
    "onUpdate:modelValue":
      _cache[0] ||
      (_cache[0] = ($event) => ($setup.inputValue = $event)),
  },
  null,
  8,
  ["modelValue"]
),
_createElementVNode(
  "p",
  null,
  "input value is: " + _toDisplayString($setup.inputValue),
  1
  /* TEXT */
),

從這兩個(gè)函數(shù)的名字我想你也能猜出來(lái)他們的作用是創(chuàng)建虛擬DOM,再仔細(xì)一看這兩個(gè)函數(shù)不就是對(duì)應(yīng)的我們template模塊中的這兩行代碼嗎。

<CommonChild v-model="inputValue" />
<p>input value is: {{ inputValue }}</p>

第一個(gè)_createVNode函數(shù)對(duì)應(yīng)的是CommonChild,第二個(gè)_createElementVNode對(duì)應(yīng)的是p標(biāo)簽。我們將重點(diǎn)放在_createVNode函數(shù)上,從import導(dǎo)入來(lái)看_createVNode函數(shù)是從vue中導(dǎo)出的createVNode函數(shù)。你是不是覺(jué)得createVNode這個(gè)名字比較熟悉呢,其實(shí)在 vue官網(wǎng)中有提到。

h() 是 hyperscript 的簡(jiǎn)稱——意思是“能生成 HTML (超文本標(biāo)記語(yǔ)言) 的 JavaScript”。這個(gè)名字來(lái)源于許多虛擬 DOM 實(shí)現(xiàn)默認(rèn)形成的約定。一個(gè)更準(zhǔn)確的名稱應(yīng)該是 createVnode(),但當(dāng)你需要多次使用渲染函數(shù)時(shí),一個(gè)簡(jiǎn)短的名字會(huì)更省力。

vue官網(wǎng)中h() 函數(shù)用于生成虛擬DOM,其實(shí)h()函數(shù)底層就是調(diào)用的createVnode函數(shù)。同樣的createVnode函數(shù)和h() 函數(shù)接收的參數(shù)也差不多,第一個(gè)參數(shù)可以是一個(gè)組件對(duì)象也可以是像p這樣的html標(biāo)簽,也可以是一個(gè)虛擬DOM。第二個(gè)參數(shù)為給組件或者h(yuǎn)tml標(biāo)簽傳遞的props屬性或者attribute。第三個(gè)參數(shù)是該節(jié)點(diǎn)的children子節(jié)點(diǎn)?,F(xiàn)在我們?cè)賮?lái)仔細(xì)看這個(gè)_createVNode函數(shù)你應(yīng)該已經(jīng)明白了:

_createVNode(
  $setup["CommonChild"],
  {
    modelValue: $setup.inputValue,
    "onUpdate:modelValue":
      _cache[0] ||
      (_cache[0] = ($event) => ($setup.inputValue = $event)),
  },
  null,
  8,
  ["modelValue"]
),

我們?cè)?nbsp;Vue 3 的 setup語(yǔ)法糖到底是什么東西?文章中已經(jīng)講過(guò)了render函數(shù)中的$setup變量就是setup函數(shù)的返回值經(jīng)過(guò)Proxy處理后的對(duì)象,由于Proxy的攔截處理讓我們?cè)趖emplate中使用ref變量時(shí)無(wú)需再寫(xiě).value。在上面的setup函數(shù)中我們看到CommonChild組件對(duì)象也在返回值對(duì)象中,所以這里傳入給createVNode函數(shù)的第一個(gè)參數(shù)為CommonChild組件對(duì)象。

我們?cè)賮?lái)看第二個(gè)參數(shù)對(duì)象,對(duì)象中有兩個(gè)key,分別是modelValue和onUpdate:modelValue。這兩個(gè)key就是傳遞給CommonChild組件的兩個(gè)props,等等這里有兩個(gè)問(wèn)題。第一個(gè)問(wèn)題是這里怎么是onUpdate:modelValue,我們知道的v-model是:modelValue和@update:modelValue的語(yǔ)法糖,不是說(shuō)好的@update怎么變成了onUpdate了呢?第二個(gè)問(wèn)題是onUpdate:modelValue明顯是事件監(jiān)聽(tīng)而不是props屬性,怎么是“通過(guò)props屬性”而不是“通過(guò)事件”傳遞給了CommonChild子組件呢?

因?yàn)樵诰幾g時(shí)處理v-on事件監(jiān)聽(tīng)會(huì)將監(jiān)聽(tīng)的事件首字母變成大寫(xiě)然后在前面加一個(gè)on,塞到props屬性對(duì)象中,所以這里才是onUpdate:modelValue。所以在組件上不管是v-bind的attribute和prop,還是v-on事件監(jiān)聽(tīng),經(jīng)過(guò)編譯后都會(huì)被塞到一個(gè)大的props對(duì)象中。以on開(kāi)頭的屬性我們都視作事件監(jiān)聽(tīng),用于和普通的attribute和prop區(qū)分。所以你在組件上綁定一個(gè)onConfirm屬性,屬性值為一個(gè)handleClick的函數(shù)。在子組件中使用emit('confirm')是可以觸發(fā)handleClick函數(shù)的執(zhí)行的,但是一般情況下還是不要這樣寫(xiě),維護(hù)代碼的人會(huì)看著一臉蒙蔽的。

我們接著來(lái)看傳遞給CommonChild組件的這兩個(gè)屬性值。

{
  modelValue: $setup.inputValue,
  "onUpdate:modelValue":
    _cache[0] ||
    (_cache[0] = ($event) => ($setup.inputValue = $event)),
}

第一個(gè)modelValue的屬性值是$setup.inputValue。前面我們已經(jīng)講過(guò)了$setup.inputValue就是指向setup中定義的名為inputValue的ref變量,所以第一個(gè)屬性的作用就是給CommonChild組件添加:modelValue="inputValue"的屬性。

我們?cè)賮?lái)看第二個(gè)屬性onUpdate:modelValue,屬性值為_(kāi)cache[0] ||(_cache[0] = ($event) => ($setup.inputValue = $event))。這里為什么要加一個(gè)_cache緩存呢?原因是每次頁(yè)面刷新都會(huì)重新觸發(fā)render函數(shù)的執(zhí)行,如果不加緩存那不就變成了每次執(zhí)行render函數(shù)都會(huì)生成一個(gè)事件處理函數(shù)。這里的事件處理函數(shù)也很簡(jiǎn)單,接收一個(gè)$event變量然后賦值給setup中的inputValue變量。接收的$event變量就是我們?cè)谧咏M件中調(diào)用emit觸發(fā)事件傳過(guò)來(lái)的第二個(gè)變量,比如:emit('update:modelValue', 'helllo word')。為什么是第二個(gè)變量呢?是因?yàn)閑mit函數(shù)接收的第一個(gè)變量為要觸發(fā)的事件名稱。所以第二個(gè)屬性的作用就是給CommonChild組件添加@update:modelValue的事件綁定。

編譯時(shí)如何處理v-model

前面我們已經(jīng)講過(guò)了在運(yùn)行時(shí)已經(jīng)拿到了key為modelValue和onUpdate:modelValue的props屬性對(duì)象了,我們知道這個(gè)props屬性對(duì)象是在編譯時(shí)由v-model指令編譯而來(lái)的,那在這個(gè)編譯過(guò)程中是如何處理v-model指令的呢?請(qǐng)看下面編譯時(shí)的流程圖:

compile-progresscompile-progress

首先會(huì)調(diào)用parse函數(shù)將template模塊中的代碼轉(zhuǎn)換為AST抽象語(yǔ)法樹(shù),此時(shí)使用v-model的node節(jié)點(diǎn)的props屬性中還是v-model。接著會(huì)調(diào)用transform函數(shù),經(jīng)過(guò)transform函數(shù)處理后在node節(jié)點(diǎn)中多了一個(gè)codegenNode屬性。在codegenNode屬性中我們看到?jīng)]有v-model指令,取而代之的是modelValue和onUpdate:modelValue屬性。經(jīng)過(guò)transform函數(shù)處理后已經(jīng)將v-model指令編譯為modelValue和onUpdate:modelValue屬性,此時(shí)還是AST抽象語(yǔ)法樹(shù)。所以接下來(lái)就是調(diào)用generate函數(shù)將AST抽象語(yǔ)法樹(shù)轉(zhuǎn)換為render函數(shù),到此為止編譯時(shí)做的事情已經(jīng)做完了。

parse函數(shù)

首先是使用parse函數(shù)將template模塊中的代碼編譯成AST抽象語(yǔ)法樹(shù),在這個(gè)過(guò)程中會(huì)使用到大量的正則表達(dá)式對(duì)字符串進(jìn)行解析。我們直接來(lái)看編譯后的AST抽象語(yǔ)法樹(shù)是什么樣子:

圖片圖片

從上圖中我們可以看到使用v-model指令的node節(jié)點(diǎn)中有了name為model和rawName為v-model的props了,明顯可以看出將template中code代碼字符串轉(zhuǎn)換為AST抽象語(yǔ)法樹(shù)時(shí)沒(méi)有處理v-model指令。那么什么時(shí)候處理的v-model指令呢?

transform函數(shù)

其實(shí)是在后面的一個(gè)transform函數(shù)中處理的,在這個(gè)函數(shù)中主要調(diào)用的是traverseNode函數(shù)處理AST抽象語(yǔ)法樹(shù)。在traverseNode函數(shù)中會(huì)去遞歸的去處理AST抽象語(yǔ)法樹(shù)中的所有node節(jié)點(diǎn),這也解釋了為什么還要在transform函數(shù)中再抽取出來(lái)一個(gè)traverseNode函數(shù)。

我們?cè)賮?lái)思考一個(gè)問(wèn)題,由于traverseNode函數(shù)會(huì)處理node節(jié)點(diǎn)的所有情況,比如v-model指令、v-for指令、v-on、v-bind。如果將這些的邏輯全部都放到traverseNode函數(shù)中,那traverseNode函數(shù)的體量將會(huì)是非常大的。所以抽取出來(lái)一個(gè)nodeTransforms的概念,這個(gè)nodeTransforms是一個(gè)數(shù)組。里面存了一組transform函數(shù),用于處理node節(jié)點(diǎn)。每個(gè)transform函數(shù)都有自己獨(dú)有的作用,比如transformModel函數(shù)用于處理v-model指令,transformIf函數(shù)用于處理v-if指令。我們來(lái)看看經(jīng)過(guò)transform函數(shù)處理后的AST抽象語(yǔ)法樹(shù)是什么樣的:

從上圖中我們可以看到同一個(gè)使用v-model指令的node節(jié)點(diǎn),經(jīng)過(guò)transform函數(shù)處理后的和第一步經(jīng)過(guò)parse函數(shù)處理后比起來(lái)node節(jié)點(diǎn)最外層多了一個(gè)codegenNode屬性。

我們接下來(lái)看看codegenNode屬性里面是什么樣的:

從上圖中我們可以看到在codegenNode中還有一個(gè)props屬性,在props屬性下面還有一個(gè)properties屬性。這個(gè)properties屬性是一個(gè)數(shù)組,里面就是存的是node節(jié)點(diǎn)經(jīng)過(guò)transform函數(shù)處理后的props屬性的內(nèi)容。我們看到properties數(shù)組中的每一個(gè)item都有key和value屬性,我想你應(yīng)該已經(jīng)反應(yīng)過(guò)來(lái)了,這個(gè)key和value分別對(duì)應(yīng)的是props屬性中的屬性名和屬性值。從上圖中我們看到第一個(gè)屬性的屬性名key的值為modelValue,屬性值value為$setup.inputValue。這個(gè)剛好就對(duì)應(yīng)上v-model指令編譯后的:modelValue="$setup.inputValue"。

我們?cè)賮?lái)接著看第二個(gè)屬性:

圖片圖片

從上圖中我們同樣也可以看到第二個(gè)屬性的屬性名key的值為onUpdate:modelValue,屬性值value的值拼起來(lái)就是為一串箭頭函數(shù),和我們前面編譯后的代碼一模一樣。第二個(gè)屬性剛好就對(duì)應(yīng)上v-model指令編譯后的@update:modelValue="($event) => ($setup.inputValue = $event)"。

從上面的分析我們看到經(jīng)過(guò)transform函數(shù)的處理后已經(jīng)將v-model指令處理為對(duì)應(yīng)的代碼了,接下來(lái)我們要做的事情就是調(diào)用generate函數(shù)將AST抽象語(yǔ)法樹(shù)轉(zhuǎn)換成render函數(shù)

generate函數(shù)

在generate函數(shù)中會(huì)遞歸遍歷AST抽象語(yǔ)法樹(shù),然后生成對(duì)應(yīng)的瀏覽器可執(zhí)行的js代碼。如下圖:

圖片圖片

從上圖中我們可以看到經(jīng)過(guò)generate函數(shù)處理后生成的render函數(shù)和我們之前在瀏覽器的network中看到的經(jīng)過(guò)編譯后的index.vue文件中的render函數(shù)一模一樣。這也證明了modelValue屬性和@update:modelValue事件塞到組件上是在編譯時(shí)進(jìn)行的。

總結(jié)

現(xiàn)在我們可以回答前面提的兩個(gè)問(wèn)題了:

  • v-model指令是如何變成組件上的modelValue屬性和@update:modelValue事件呢?首先會(huì)調(diào)用parse函數(shù)將template模塊中的代碼轉(zhuǎn)換為AST抽象語(yǔ)法樹(shù),此時(shí)使用v-model的node節(jié)點(diǎn)的props屬性中還是v-model。接著會(huì)調(diào)用transform函數(shù),經(jīng)過(guò)transform函數(shù)處理后在node節(jié)點(diǎn)中多了一個(gè)codegenNode屬性。在codegenNode屬性中我們看到?jīng)]有v-model指令,取而代之的是modelValue和onUpdate:modelValue屬性。經(jīng)過(guò)transform函數(shù)處理后已經(jīng)將v-model指令編譯為modelValue和onUpdate:modelValue屬性。其實(shí)在運(yùn)行時(shí)onUpdate:modelValue屬性就是等同于@update:modelValue事件。接著就是調(diào)用generate函數(shù),將AST抽象語(yǔ)法樹(shù)生成render函數(shù)。然后在瀏覽器中執(zhí)行render函數(shù)時(shí),將拿到的modelValue和onUpdate:modelValue屬性塞到組件對(duì)象上,所以在組件上就多了兩個(gè)modelValue屬性和@update:modelValue事件。
  • 將v-model指令轉(zhuǎn)換為modelValue屬性和@update:modelValue事件這一過(guò)程是在編譯時(shí)還是運(yùn)行時(shí)進(jìn)行的呢?從上面的問(wèn)題答案中我們可以知道將v-model指令轉(zhuǎn)換為modelValue屬性和@update:modelValue事件這一過(guò)程是在編譯時(shí)進(jìn)行的。

在transform函數(shù)中是調(diào)用transformModel函數(shù)處理v-model指令,這篇文章沒(méi)有深入到transformModel函數(shù)源碼內(nèi)去講解。如果大家對(duì)transformModel函數(shù)的源碼感興趣請(qǐng)?jiān)谠u(píng)論區(qū)留言或者給我發(fā)信息,我會(huì)在后面的文章安排上。

責(zé)任編輯:武曉燕 來(lái)源: 前端歐陽(yáng)
相關(guān)推薦

2021-09-07 10:44:33

Java 注解開(kāi)發(fā)

2021-03-26 08:01:29

v-model指令模板

2024-02-22 15:36:23

Java內(nèi)存模型線程

2021-12-08 06:53:29

面試動(dòng)態(tài)代理

2022-09-29 07:30:57

數(shù)據(jù)庫(kù)索引字段

2021-11-09 14:08:45

DockerDockerfileJava

2024-02-04 10:08:34

2021-02-19 10:02:57

HTTPSJava安全

2024-12-25 15:44:15

2021-03-03 17:26:45

面試Synchronous底層

2022-05-23 08:43:02

BigIntJavaScript內(nèi)置對(duì)象

2024-07-22 14:09:22

@AsyncJava

2015-08-13 10:29:12

面試面試官

2023-11-15 09:14:27

Java值傳遞

2025-10-21 08:06:20

2022-07-15 08:22:42

對(duì)象符串鍵Symbol

2023-12-06 09:10:28

JWT微服務(wù)

2024-05-11 15:11:44

系統(tǒng)軟件部署

2023-02-08 07:04:20

死鎖面試官單元

2021-04-19 18:56:58

大數(shù)字符串運(yùn)算
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

神马一区二区三区| 制服丨自拍丨欧美丨动漫丨| 波多野结衣亚洲| 亚洲国产成人午夜在线一区| 51精品国产人成在线观看| 国内免费精品视频| 99成人在线视频| 亚洲国产精品小视频| 999精品视频在线| 麻豆福利在线观看| 国产欧美日韩不卡免费| 2020国产精品久久精品不卡| 久久精品视频5| 亚洲午夜精品一区 二区 三区| 日韩精品视频观看| 久草福利在线观看| 日韩制服诱惑| 天天做天天摸天天爽国产一区| 国产又粗又爽又黄的视频| 午夜av免费观看| 国产精品99精品久久免费| 国产精品入口免费视频一| 日产精品久久久久久久| 91精品国偷自产在线电影| 亚洲人高潮女人毛茸茸| 男人网站在线观看| 国产精品亚洲一区二区在线观看| 色94色欧美sute亚洲线路一久| 国产乱子伦精品无码专区| 欧美精品videos另类| 久久久久国产精品麻豆ai换脸| 大波视频国产精品久久| 国产情侣av在线| 日本不卡在线视频| 国产91色在线播放| 自拍偷拍欧美亚洲| 亚洲一级特黄| 欧美日本高清一区| av成人免费网站| 狠狠做六月爱婷婷综合aⅴ| 亚洲国产美女久久久久| 激情综合激情五月| 中文字幕日韩在线| 日韩免费视频线观看| 又色又爽又黄视频| 色成人综合网| 制服丝袜亚洲播放| 欧美精品 - 色网| 欧美亚洲福利| 欧美精品高清视频| 九九九九九国产| 亚洲精品成人一区| 欧美日韩视频在线一区二区| 波多野结衣xxxx| 国产精品久久久久久久久久齐齐 | 日韩经典一区二区| 日韩免费在线看| 免费看一级视频| 日日摸夜夜添夜夜添国产精品| 91av在线看| 亚洲欧美另类在线视频| 老司机午夜免费精品视频| 热久久视久久精品18亚洲精品| 永久免费无码av网站在线观看| 久久久亚洲一区| 国产精品一区二区三区久久 | 久久99久久精品| 成人黄色短视频在线观看| 91超薄丝袜肉丝一区二区| 黄页网站大全一区二区| 成人区精品一区二区| 欧美一级一区二区三区| 91麻豆.com| 亚洲午夜精品一区二区| 成人看av片| 亚洲综合999| 成人毛片视频网站| 秋霞国产精品| 欧美一区二区三区四区视频| ass极品水嫩小美女ass| 亚州av一区| 色噜噜亚洲精品中文字幕| 印度午夜性春猛xxx交| 在线精品亚洲| 国产精品久久久久久中文字| 国产又粗又黄又爽的视频| 国产高清不卡二三区| 久久99久久精品国产| 91激情在线| 一区二区三区中文在线| 无码aⅴ精品一区二区三区浪潮| 成人国产网站| 亚洲二区中文字幕| 亚洲自拍偷拍图| 欧美成人69av| 国产精品久久久久国产a级| 国产露脸国语对白在线| 99热精品一区二区| 老司机av福利| 成年美女黄网站色大片不卡| 91精品国产综合久久久蜜臀粉嫩 | 自拍自偷一区二区三区| 日韩视频亚洲视频| 日韩伦人妻无码| 麻豆成人久久精品二区三区红| 国产99在线免费| av电影在线观看| 欧美日韩国产精品| 亚洲国产日韩在线一区| 精品freesex老太交| 欧美激情中文字幕在线| 中文字幕乱码视频| 91麻豆国产在线观看| 超碰超碰超碰超碰超碰| 国产综合色在线观看| 亚洲成人在线视频播放| 国产极品国产极品| 精品一区二区三区在线播放视频| 九9re精品视频在线观看re6| 亚洲丝袜精品| 在线播放/欧美激情| 欧美18—19性高清hd4k| 性欧美xxxx大乳国产app| 国产精品裸体一区二区三区| 激情视频在线观看| 欧美四级电影在线观看| 51自拍视频在线观看| 日韩免费高清| 国产精品电影久久久久电影网| 国产小视频一区| 自拍偷拍欧美激情| www.久久av.com| 第一会所sis001亚洲| 日本久久久久久久| 天堂а√在线8种子蜜桃视频| 亚洲综合图片区| 丰满人妻一区二区三区53视频| 日韩精品欧美| 国产精品专区一| shkd中文字幕久久在线观看| 色哟哟精品一区| 中文字幕丰满乱子伦无码专区| 激情成人亚洲| 韩日午夜在线资源一区二区| 国产免费拔擦拔擦8x在线播放| 精品国产乱码久久久久久图片| 久久r这里只有精品| 国产美女在线精品| 亚洲五码在线观看视频| 免费观看亚洲天堂| 九九精品在线视频| 免费国产黄色片| 亚洲aⅴ怡春院| 中文字幕乱码在线| 亚洲欧美日韩国产| 视频在线一区二区三区| jizzyou欧美16| 色婷婷久久av| 国产成人毛毛毛片| 亚洲综合久久久久| jizz日本免费| 免费在线看成人av| 天天干天天色天天爽| 午夜久久av| 2024亚洲男人天堂| av在线电影观看| 正在播放亚洲一区| 精品小视频在线观看| 99精品国产91久久久久久| 成年人视频网站免费观看| 精品一区二区三区的国产在线观看| 国产精品一区二区久久国产| www视频在线免费观看| 欧美mv日韩mv| 精品国产乱子伦| 国产精品国产三级国产三级人妇| 18深夜在线观看免费视频| 亚洲国产一区二区精品专区| 日本公妇乱淫免费视频一区三区| 日韩伦理一区二区| 国模视频一区二区三区| fc2在线中文字幕| 日韩视频国产视频| 国产成人精品777777| 亚洲色图欧美偷拍| 中文字幕 亚洲一区| 免费观看在线色综合| 日本欧美视频在线观看| 国内亚洲精品| 国产精品大全| 亚洲电影有码| 午夜精品视频在线| 在线播放毛片| 日韩av网站电影| 97人妻一区二区精品免费视频| 亚洲一区二区偷拍精品| 国产又黄又粗视频| 丁香亚洲综合激情啪啪综合| 9久久婷婷国产综合精品性色 | 欧美日韩大片免费观看| 成人欧美一区二区三区在线| 手机在线理论片| 久久的精品视频| 国产在线黄色| 亚洲国产精久久久久久久| 国产又大又黄的视频| 色网站国产精品| 免费观看一级视频| 国产精品乱码妇女bbbb| aa片在线观看视频在线播放| 紧缚奴在线一区二区三区| 美女福利视频在线| 红桃视频欧美| 永久免费网站视频在线观看| 成人3d动漫在线观看| 国产精品一区二区a| 亚洲日本免费电影| 国产成人综合久久| 国产白丝在线观看| 久久影院在线观看| h视频在线免费| 亚洲欧洲中文天堂| 天天av综合网| 亚洲二区中文字幕| 不卡视频免费在线观看| 51精品国自产在线| 最近中文字幕在线观看| 欧美性猛交xxxx乱大交| 日本a在线观看| 亚洲一区二区3| 欧美激情国产精品免费| 日韩美女视频19| 人与动物性xxxx| 中文字幕av不卡| 免费一级特黄3大片视频| 99国产精品视频免费观看| 三上悠亚 电影| 国产精品123| 波多野结衣在线免费观看| 国产在线精品国自产拍免费| 日本中文字幕二区| 美女网站色91| 日本免费色视频| 精品一区二区三区影院在线午夜| 天天爽人人爽夜夜爽| 麻豆精品一区二区三区| 潘金莲激情呻吟欲求不满视频| 青青草伊人久久| 天堂网在线免费观看| 美女一区二区三区在线观看| 亚洲欧美日韩一级| 久久精品国产第一区二区三区| 91 在线视频观看| 国产久卡久卡久卡久卡视频精品| 精品人妻一区二区三| 粉嫩13p一区二区三区| 动漫av在线免费观看| caoporen国产精品视频| 亚洲AV无码国产精品| 国产日韩欧美制服另类| 国产黄色录像视频| 中文字幕一区二区三中文字幕| 五月天免费网站| 亚洲欧美日韩久久精品| 亚洲激情视频一区| 欧美日韩国产在线| 亚洲中文无码av在线| 欧美精品久久一区二区三区| 亚洲成熟女性毛茸茸| 日韩av最新在线| www在线免费观看| 欧美成人免费小视频| 精品丝袜在线| 国产精品中文在线| 成人午夜网址| 日韩美女一区| 黑人一区二区| 精品国产成人av在线免| 久久精品国产99| 99精品一区二区三区无码吞精| 国产色综合一区| 欧美三级免费看| 岛国视频午夜一区免费在线观看| 亚洲精品一区二区二区| 日韩精品中文字幕一区二区三区 | 欧美激情一区二区久久久| 中文字幕在线官网| 91久久久亚洲精品| 欧美挤奶吃奶水xxxxx| 亚洲7777| 亚洲一区二区免费看| 中文字幕66页| 91在线观看污| 欧美老熟妇一区二区三区| 欧美日韩午夜视频在线观看| 一卡二卡在线观看| 亚洲精品按摩视频| 黄色免费在线看| 日本一区二区在线播放| 国产精品亚洲欧美一级在线| 欧美精品一区二区三区久久| 中文字幕一区二区三区久久网站| 国产成人无码a区在线观看视频| 久久电影网站中文字幕| 丰满圆润老女人hd| 亚洲国产婷婷综合在线精品| 91tv国产成人福利| 亚洲偷熟乱区亚洲香蕉av| 岛国在线视频网站| 92看片淫黄大片欧美看国产片| 国产中文字幕一区二区三区| 久草视频这里只有精品| 精品中文字幕一区二区小辣椒 | 亚洲卡通动漫在线| 国产精品51麻豆cm传媒| 亚洲精品久久久久久久久| 四虎影院观看视频在线观看 | 中文字幕在线播放不卡一区| 天堂网av手机版| 精品999在线播放| 国产精品久久麻豆| 成人国产精品av| 日韩国产一区二区| 欧美国产日韩在线播放| 不卡的av中国片| 国产一级片播放| 欧美一区二区三区免费大片| 亚洲成人三级| 国产精品女人网站| 久久99免费视频| 黑人糟蹋人妻hd中文字幕| 97久久超碰国产精品| 国产在线一二区| 精品电影一区二区三区| 中文字幕资源网在线观看| 川上优av一区二区线观看| 成人激情在线| 日韩一区二区三区不卡视频| 国产欧美在线观看一区| 成年人晚上看的视频| 亚洲欧美国产一区二区三区| 涩涩视频网站在线观看| 久久久久一区二区| 翔田千里一区二区| 偷拍女澡堂一区二区三区| 欧美日韩激情美女| 你懂的视频在线观看| 日本成熟性欧美| 狠狠色丁香婷婷综合影院| 欧美大尺度做爰床戏| 中文字幕一区二区三区乱码在线| 伊人网av在线| 日韩在线观看免费全| 蜜桃在线一区| 阿v天堂2017| 久久一二三国产| 国产午夜无码视频在线观看| 国产亚洲精品高潮| 欧美黄色成人| 樱空桃在线播放| 国产成人免费在线观看不卡| 日本三级欧美三级| 亚洲欧洲一区二区三区久久| 国产成人午夜性a一级毛片| 91免费视频黄| 成人综合在线观看| 欧美bbbbbbbbbbbb精品| 亚洲色图35p| 一区在线不卡| 福利视频一区二区三区四区| 久久免费午夜影院| 伊人久久国产精品| 欧美激情久久久久久| 美女呻吟一区| 亚洲第一中文av| 亚洲乱码国产乱码精品精可以看| 粉嫩av一区二区夜夜嗨| 人人澡人人澡人人看欧美| 99久久精品费精品国产| 野战少妇38p| 在线看日本不卡| 18网站在线观看| 欧美成人综合一区| 韩日欧美一区二区三区| 国产福利拍拍拍| www国产亚洲精品久久网站| 成人h动漫免费观看网站| 亚洲人成无码www久久久| 亚洲日本护士毛茸茸| 日韩a级作爱片一二三区免费观看| 国产精品永久在线| 99国产精品| av最新在线观看| 亚洲精品影视在线观看| 久久综合给合| 男人舔女人下面高潮视频| 一区二区三区四区五区视频在线观看| 青青草免费在线| 成人91免费视频| 免费成人在线视频观看|