精品欧美一区二区三区在线观看 _久久久久国色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)

亚洲成精国产精品女| 综合国产在线| 日本高清成人免费播放| 亚洲精品一区二区三区av| 国产精品国产av| 国产精品www994| 亚洲视频一区二区三区| 成人精品久久一区二区三区| 中日韩一级黄色片| 国产精品18hdxxxⅹ在线| 色综合天天综合网天天狠天天| 午夜精品亚洲一区二区三区嫩草| 国产熟女一区二区三区五月婷| 亚洲国产高清一区二区三区| 一个色综合导航| 国产a√精品区二区三区四区| 欧美91看片特黄aaaa| 国产精品久久久久久久久免费相片 | www.欧美国产| 久久婷婷激情| 欧美激情xxxxx| 五月激情四射婷婷| 牛牛精品成人免费视频| 在线播放国产精品二区一二区四区| 久久综合久久网| 在线观看麻豆蜜桃| 99麻豆久久久国产精品免费| 91久久久久久国产精品| 久久久久久久久久久久久久av| 91麻豆精品在线| 亚洲aa在线| 精品电影一区二区三区| 亚洲色图狂野欧美| 亚洲精品大片www| 2020国产精品视频| 久久嫩草捆绑紧缚| 九九在线高清精品视频| 日韩欧美自拍偷拍| 日韩欧美国产片| 深夜成人影院| 精品欧美aⅴ在线网站| 成年人视频大全| 免费黄网在线观看| 欧美激情在线免费观看| 麻豆久久久av免费| 四虎永久在线观看| 国产一区二区三区蝌蚪| 国产精品亚洲美女av网站| 国产在线观看黄色| 国产一区二区三区久久久久久久久| 久久大大胆人体| 999福利视频| 日韩免费视频| 黄色一区二区在线观看| 99精品视频网站| 日本亚洲精品| 中文字幕一区二区在线播放| 色综合电影网| 成人亚洲性情网站www在线观看| 99精品欧美一区二区三区综合在线| 99热最新在线| 噜噜噜久久,亚洲精品国产品| 国产精品18久久久久久久网站| 91香蕉国产在线观看| 亚洲综合精品视频| 精品在线播放午夜| 亚洲一区中文字幕在线观看| 99国产精品久久久久久久成人| 狠狠网亚洲精品| 成人性教育视频在线观看| 国产一区二区三区黄片| 国内精品伊人久久久久av一坑| 国产中文字幕亚洲| 国产乱淫av片免费| 国产精品18久久久久久久久| yy111111少妇影院日韩夜片| 手机av在线免费观看| 99久久精品免费看国产| 麻豆久久久av免费| 日本天堂在线观看| 一区二区三区在线视频免费观看| 欧美狂野激情性xxxx在线观| 理论不卡电影大全神| 一本大道综合伊人精品热热| 一区二区三区 欧美| 欧美成人毛片| 欧美一区二区三区四区高清| 久久久精品国产亚洲| 亚洲a一级视频| 国产绿帽刺激高潮对白| 懂色一区二区三区免费观看| 精品国产乱码久久久久久久软件| 青青草超碰在线| 国产欧美日韩激情| 51xx午夜影福利| 超碰资源在线| 精品视频一区二区三区免费| 韩国三级丰满少妇高潮| 欧美aaaaaaaa牛牛影院| 色哟哟入口国产精品| 九九视频免费观看| 久久久久久久尹人综合网亚洲| 成人春色激情网| 欧美性受xxxx狂喷水| 中文字幕乱码久久午夜不卡 | 成年人午夜视频在线观看| 成人国产精品久久久久久亚洲| 日本人妻一区二区三区| 亚洲色图美女| 久久精品久久久久| xxxx.国产| 国产酒店精品激情| 欧美下载看逼逼| 深夜国产在线播放| 一区二区三区四区中文字幕| 欧美色18zzzzxxxxx| 99久久婷婷这里只有精品| 欧美日本亚洲视频| 成年人视频免费| 日韩色淫视频| 欧美三级视频在线观看| 国产成人精品无码片区在线| 成年人视频免费在线播放| 色狠狠综合天天综合综合| 夜夜夜夜夜夜操| 日韩丝袜视频| 欧美激情国产精品| 夜夜嗨av禁果av粉嫩avhd| 91农村精品一区二区在线| 可以在线看黄的网站| 97人人做人人爽香蕉精品| 亚洲成av人片在线观看香蕉| 欧美手机在线观看| 日韩avvvv在线播放| 国产综合色一区二区三区| 国内精品久久久久国产| 在线观看三级视频欧美| 性欧美丰满熟妇xxxx性久久久| 中文字幕一区二区av| 国产精品国产福利国产秒拍| 人妻无码中文字幕| 亚洲一区在线观看视频| 男插女视频网站| 水蜜桃精品av一区二区| 国产精品免费久久久| 九九在线视频| 欧美丝袜美女中出在线| 久久福利小视频| 99国产精品| 国产欧美日韩综合一区在线观看| 免费在线观看的电影网站| 日韩情涩欧美日韩视频| 久久久久久久久久99| 国产一二精品视频| 91视频成人免费| 国产精品一区二区三区av| 中文字幕亚洲一区| 亚洲一区精品在线观看| 国产精品久久99| 午夜精品久久久久久久99热影院| 色777狠狠狠综合伊人| 国产精品爽爽爽爽爽爽在线观看| 成人18在线| 欧美在线观看视频一区二区三区 | 国产尤物99| 四虎影院观看视频在线观看 | 粉色视频免费看| 国产精品97| 亚洲xxxxx电影| 欧美日韩色网| 亚洲国产精品视频在线观看| 天堂在线免费观看视频| 国产欧美一区二区三区网站 | 亚洲午夜精品一区二区 | 91久久爱成人| 免费在线观看av电影| 亚洲黄色av网站| 国产寡妇亲子伦一区二区三区四区| 国产欧美一区二区精品忘忧草 | 国产一区二区三区在线观看免费视频| 久久久久久久久久av| 中文字幕久热精品视频在线| 91成人天堂久久成人| 久久中文字幕免费| 欧美国产精品中文字幕| 欧美三级电影一区| 91色国产在线| 五月激情综合| 国产精品久久亚洲7777| 在线成人av观看| 中文字幕最新精品| 丰满人妻一区二区三区免费视频| 欧美日韩色婷婷| 91制片厂在线| av电影在线观看不卡| 北条麻妃av高潮尖叫在线观看| 日韩在线高清| 国产精品一区二区欧美黑人喷潮水| 国产免费拔擦拔擦8x在线播放| 亚洲人在线视频| 国产女人高潮毛片| 欧美性xxxxxxx| 成年人二级毛片| 99久久99久久久精品齐齐| 久草福利视频在线| 在线成人欧美| 永久免费精品视频网站| 激情亚洲另类图片区小说区| 国产精品久久久久久一区二区| 18videosex性欧美麻豆| 亚洲人成网在线播放| 99精品视频免费看| 在线观看一区日韩| 538任你躁在线精品视频网站| 综合精品一区| 欧美日韩一二区| 精品少妇一区二区三区密爱| 成人精品国产一区二区4080| 91国产精品视频在线观看| 影音先锋中文字幕一区| 亚洲三区视频| 亚洲欧美日韩精品永久在线| 色一区在线观看| 久草国产在线视频| 中文字幕永久在线不卡| 久久久久久国产精品无码| 国产成人免费在线| 天天影视色综合| 七七婷婷婷婷精品国产| 六月激情综合网| 伊人久久亚洲影院| 久久久久久久免费视频| 日韩精品影视| 日韩影片在线播放| 女优一区二区三区| 久久国产手机看片| 果冻天美麻豆一区二区国产| 亚洲综合中文字幕在线| 精品久久福利| 国产精品国语对白| 免费看av不卡| 日韩av观看网址| 午夜久久中文| 91国产在线精品| bl在线肉h视频大尺度| 欧美多人爱爱视频网站| 91麻豆一二三四在线| 久久久精品久久| 日本中文字幕在线播放| 搡老女人一区二区三区视频tv| 999精品免费视频| 午夜精品网站| 午夜啪啪福利视频| 欧美在线不卡| 不卡一区在线观看| 18禁网站免费无遮挡无码中文| 伊人情人综合网| 男人的天堂视频在线| 欧美精品91| 久久亚洲国产成人精品无码区| 欧美日韩亚洲一区三区 | 超碰免费在线97| 亚洲成av人乱码色午夜| 男人天堂一区二区| 亚洲精品999| 免费一级毛片在线观看| 国产午夜精品一区理论片飘花| 二区在线观看| www亚洲欧美| 污污的视频在线观看| 欧美精品成人91久久久久久久| 大黄网站在线观看| 欧美在线观看一区二区三区| 国模套图日韩精品一区二区| 国产精国产精品| 在线免费成人| 国产精品久久久久免费| 伊人成综合网伊人222| 一道精品一区二区三区| 欧美成熟视频| 欧美日韩成人免费视频| 日韩电影在线免费看| 久久精品视频在线观看免费| 成人国产精品免费观看视频| 五月开心播播网| 中文在线一区二区| 欧美成人三级视频| 第一福利永久视频精品| 国产九色91回来了| 欧美成va人片在线观看| 天天干天天做天天操| 色多多国产成人永久免费网站| 成人影欧美片| 日韩av免费一区| 国产亚洲高清在线观看| 久久香蕉综合色| 亚洲一级淫片| 欧洲黄色一级视频| 国内不卡的二区三区中文字幕| 欧美xxxxx少妇| 中文字幕精品三区| 黄网站免费在线| 欧美日韩专区在线| 天堂网在线观看视频| 中文字幕欧美日韩va免费视频| 色呦呦久久久| 国产精品一区=区| 国产伦理久久久久久妇女| 天天久久人人| 国产亚洲激情| 久久久久亚洲av无码麻豆| 久久你懂得1024| 久久久久九九九| aaa国产精品视频| 亚洲乱码国产乱码精品天美传媒| 欧美精品三区| 久久久久九九视频| 99精品全国免费观看| 亚洲午夜在线电影| 国产精品久久久久久免费播放| 亚洲美女性视频| 美女日批视频在线观看| 国产区精品在线观看| 美女毛片一区二区三区四区| 337p亚洲精品色噜噜狠狠p| 青青草97国产精品免费观看| 影音先锋黄色资源| 亚洲综合清纯丝袜自拍| 91成人国产综合久久精品| 国产香蕉97碰碰久久人人| av影院在线| 91日韩久久| 中国精品18videos性欧美| 9久久婷婷国产综合精品性色 | 亚洲情侣在线| 九九热99视频| 国产精品区一区二区三区| 成人a v视频| 亚洲日本成人网| 亚洲欧美电影| 欧美成ee人免费视频| 亚洲日本国产| 日本精品一二三区| 亚洲最大成人综合| 99视频在线观看免费| 色婷婷综合成人| 成人在线免费电影网站| 午夜老司机精品| 麻豆精品视频在线观看视频| 公肉吊粗大爽色翁浪妇视频| 在线观看亚洲专区| 成年人在线视频| 国产精品三级在线| 久久精品不卡| 亚洲男人天堂2021| 亚洲欧美国产三级| www.97av| 性视频1819p久久| 加勒比久久高清| 欧美三级一级片| 国产午夜三级一区二区三| 自拍偷拍精品视频| 久热精品视频在线观看一区| 视频一区日韩精品| 国产无限制自拍| 久久久五月婷婷| 影音先锋国产资源| 美女av一区二区| 国产区精品视频在线观看豆花| 国产精品久久中文字幕| 久久久久久久久一| 中文字幕第99页| 欧美猛少妇色xxxxx| h视频久久久| 黄色a级片免费| 亚洲欧美在线另类| 黄色www视频| 国产成人精品一区| 亚洲成人av| 亚洲精品乱码久久| 欧洲生活片亚洲生活在线观看| 超碰个人在线| 国产一区自拍视频| 日本免费在线视频不卡一不卡二 | 日韩中字在线| xxxxwww一片| 日韩欧美中文字幕在线观看| 天堂地址在线www| 国产精品区一区二区三在线播放| 久久国产直播| 性欧美疯狂猛交69hd| 亚洲激情电影中文字幕| 99久久伊人| 亚洲中文字幕无码一区二区三区 | 黄在线免费观看| 国模精品一区二区三区| 免费人成网站在线观看欧美高清| 免费在线观看av网址| 亚洲欧美国内爽妇网| 欧美特黄不卡|