国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

面試官:在原生input上面使用v-model和組件上面使用有什么區(qū)別?

這篇具有很好參考價(jià)值的文章主要介紹了面試官:在原生input上面使用v-model和組件上面使用有什么區(qū)別?。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

還是上一篇面試官:來說說vue3是怎么處理內(nèi)置的v-for、v-model等指令? 文章的那個(gè)粉絲,面試官接著問了他另外一個(gè)v-model的問題。

  • 面試官:vue3的v-model都用過吧,來講講。

  • 粉絲:v-model其實(shí)就是一個(gè)語法糖,在編譯時(shí)v-model會(huì)被編譯成:modelValue屬性和@update:modelValue事件。一般在子組件中定義一個(gè)名為modelValue的props來接收父組件v-model傳遞的值,然后當(dāng)子組件表單的值變化時(shí)再使用@update:modelValue拋出事件給父組件,由父組件來更新v-model綁定的變量。

  • 面試官:你說的這個(gè)是在組件上面使用v-model,原生input上面也支持v-model,你來說說原生input上面使用v-model以及和組件上面使用v-model有什么區(qū)別?

  • 粉絲:啊,兩個(gè)不是一樣的嗎?都是:modelValue屬性和@update:modelValue事件的語法糖吖。

  • 面試官:原生input標(biāo)簽接收的是value屬性,監(jiān)聽的是input或者change事件。你說v-model會(huì)編譯成:modelValue屬性,但是input標(biāo)簽只接收value屬性,那你傳的modelValue屬性input標(biāo)簽怎么接收的?同理你說v-model會(huì)編譯成監(jiān)聽@update:modelValue事件,但是input標(biāo)簽只監(jiān)聽input或者change事件,那你傳監(jiān)聽的@update:modelValue事件又是怎么觸發(fā)的呢?

在之前的 面試官:只知道v-model是modelValue語法糖,那你可以走了 文章中我已經(jīng)講過了在組件中怎么將v-model編譯成:modelValue屬性和@update:modelValue事件,今天我們就來講講在原生input上面使用v-model和在組件上面使用有什么區(qū)別?

先說答案

來看看我畫個(gè)這個(gè)流程圖,如下:
面試官:在原生input上面使用v-model和組件上面使用有什么區(qū)別?

根據(jù)上面的流程圖,我們知道了在組件上面使用v-model和原生input上面使用v-model區(qū)別主要有三點(diǎn):

  • 組件上面的v-model編譯后會(huì)生成modelValue屬性和@update:modelValue事件。

    而在原生input上面使用v-model編譯后不會(huì)生成modelValue屬性,只會(huì)生成onUpdate:modelValue回調(diào)函數(shù)和vModelText自定義指令。(在 面試官:只知道v-model是modelValue語法糖,那你可以走了 文章中我們已經(jīng)講過了@update:modelValue事件其實(shí)等價(jià)于onUpdate:modelValue回調(diào)函數(shù))

  • 在組件上面使用v-model,是由子組件中定義一個(gè)名為modelValue的props來接收父組件使用v-model綁定的變量,然后使用這個(gè)modelValue綁定到子組件的表單中。

    在原生input上面使用v-model,是由編譯后生成的vModelText自定義指令在mountedbeforeUpdate鉤子函數(shù)中去將v-model綁定的變量值更新到原生input輸入框的value屬性,以保證v-model綁定的變量值和input輸入框中的值始終一致。

  • 在組件上面使用v-model,是由子組件使用emit拋出@update:modelValue事件,在@update:modelValue的事件處理函數(shù)中去更新v-model綁定的變量。

    而在原生input上面使用v-model,是由編譯后生成的vModelText自定義指令在created鉤子函數(shù)中去監(jiān)聽原生input標(biāo)簽的input或者change事件。在事件回調(diào)函數(shù)中去手動(dòng)調(diào)用onUpdate:modelValue回調(diào)函數(shù),然后在回調(diào)函數(shù)中去更新v-model綁定的變量。

看個(gè)例子

下面這個(gè)是我寫的一個(gè)demo,代碼如下:

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

<script setup lang="ts">
import { ref } from "vue";

const msg = ref();
</script>

上面的例子很簡單,在原生input標(biāo)簽上面使用v-model綁定了msg變量。我們接下來看看編譯后的js代碼是什么樣的,那么問題來了怎么找到編譯后的js代碼呢?

其實(shí)很簡單直接在network上面找到你的那個(gè)vue文件就行了,比如我這里的文件是index.vue,那我只需要在network上面找叫index.vue的文件就行了。但是需要注意一下network上面有兩個(gè)index.vue的js請(qǐng)求,分別是template模塊+script模塊編譯后的js文件,和style模塊編譯后的js文件。

那怎么區(qū)分這兩個(gè)index.vue文件呢?很簡單,通過query就可以區(qū)分。由style模塊編譯后的js文件的URL中有type=style的query,如下圖所示:
面試官:在原生input上面使用v-model和組件上面使用有什么區(qū)別?

接下來我們來看看編譯后的index.vue,簡化的代碼如下:

import {
  Fragment as _Fragment,
  createElementBlock as _createElementBlock,
  createElementVNode as _createElementVNode,
  defineComponent as _defineComponent,
  openBlock as _openBlock,
  toDisplayString as _toDisplayString,
  vModelText as _vModelText,
  withDirectives as _withDirectives,
  ref,
} from "/node_modules/.vite/deps/vue.js?v=23bfe016";

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

function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  return (
    _openBlock(),
    _createElementBlock(
      _Fragment,
      null,
      [
        _withDirectives(
          _createElementVNode(
            "input",
            {
              "onUpdate:modelValue":
                _cache[0] || (_cache[0] = ($event) => ($setup.msg = $event)),
            },
            null,
            512
          ),
          [[_vModelText, $setup.msg]]
        ),
        _createElementVNode(
          "p",
          null,
          "input value is: " + _toDisplayString($setup.msg),
          1
        ),
      ],
      64
    )
  );
}
_sfc_main.render = _sfc_render;
export default _sfc_main;

從上面的代碼中我們可以看到編譯后的js代碼主要分為兩塊。

第一塊是_sfc_main組件對(duì)象,里面有name屬性和setup方法。一個(gè)vue組件其實(shí)就是一個(gè)對(duì)象,這里的_sfc_main對(duì)象就是一個(gè)vue組件對(duì)象。

我們接著來看第二塊_sfc_render,從名字我想你應(yīng)該已經(jīng)猜到了他是一個(gè)render函數(shù)。執(zhí)行這個(gè)_sfc_render函數(shù)就會(huì)生成虛擬DOM,然后再由虛擬DOM生成瀏覽器上面的真實(shí)DOM。我們接下來主要看看這個(gè)render函數(shù)。

render函數(shù)

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

來看看里層的數(shù)組,數(shù)組中有兩項(xiàng)。分別是withDirectives函數(shù)和createElementVNode函數(shù),數(shù)組中的這兩個(gè)函數(shù)分別對(duì)應(yīng)的就是template中的input標(biāo)簽和p標(biāo)簽。我們主要來關(guān)注input標(biāo)簽,也就是withDirectives函數(shù)。

withDirectives函數(shù)

這個(gè)withDirectives是否覺得有點(diǎn)眼熟?他是vue提供的一個(gè)進(jìn)階API,我們平時(shí)寫業(yè)務(wù)基本不會(huì)用到他。作用是給vnode(虛擬DOM)增加自定義指令。

接收兩個(gè)參數(shù),第一個(gè)參數(shù)為需要添加指令的vnode,第二個(gè)參數(shù)是由自定義指令組成的二維數(shù)組。二維數(shù)組的第一層是表示有哪些自定義指令,第二層表示的是指令名稱、綁定值、參數(shù)、修飾符。第二層的結(jié)構(gòu)為:?[Directive, value, argument, modifiers]?。如果不需要,可以省略數(shù)組的尾元素。

舉個(gè)例子:

import { h, withDirectives } from 'vue'

// 一個(gè)自定義指令
const pin = {
  mounted() {
    /* ... */
  },
  updated() {
    /* ... */
  }
}

// <div v-pin:top.animate="200"></div>
const vnode = withDirectives(h('div'), [
  [pin, 200, 'top', { animate: true }]
])

上面這個(gè)例子定義了一個(gè)pin的自定義指令,調(diào)用h函數(shù)生成vnode傳給withDirectives函數(shù)的第一個(gè)參數(shù)。第二個(gè)參數(shù)自定義指令數(shù)組,我們這里只傳了一個(gè)pin自定義指令。來看看[Directive, value, argument, modifiers]。

  • 第一個(gè)Directive字段:“指令名稱”對(duì)應(yīng)的就是pin自定義指令。

  • 第二個(gè)value字段:“指令值”對(duì)應(yīng)的就是200。

  • 第三個(gè)字段argument字段:“參數(shù)”對(duì)應(yīng)的就是top參數(shù)。

  • 第四個(gè)字段modifiers字段:“修飾符”對(duì)應(yīng)的就是animate修飾符。

所以上面的withDirectives函數(shù)實(shí)際就是對(duì)應(yīng)的<div v-pin:top.animate="200"></div>

createElementVNode函數(shù)

看見這個(gè)函數(shù)名字我想你應(yīng)該也猜到了,作用是創(chuàng)建vnode(虛擬dom)。這個(gè)函數(shù)和vue提供的 h函數(shù)差不多,底層調(diào)用的都是一個(gè)名為createBaseVNode的函數(shù)。接收的第一個(gè)參數(shù)既可以是一個(gè)字符串 (用于原生元素) 也可以是一個(gè) Vue 組件定義。接收的第二個(gè)參數(shù)是要傳遞的 prop,第三個(gè)參數(shù)是子節(jié)點(diǎn)。

舉個(gè)例子:

createElementVNode("input", {
  value: 12,
})

上面這個(gè)例子創(chuàng)建了一個(gè)input的vnode,輸入框中的值為12

搞清楚了withDirectives函數(shù)和createElementVNode函數(shù)的作用,我們回過頭來看之前對(duì)應(yīng)input標(biāo)簽的代碼你應(yīng)該就很容易理解了。代碼如下:

_withDirectives(
  _createElementVNode(
    "input",
    {
      "onUpdate:modelValue":
        _cache[0] || (_cache[0] = ($event) => ($setup.msg = $event)),
    },
    null,
    512
  ),
  [[_vModelText, $setup.msg]]
)

調(diào)用withDirectives函數(shù),傳入兩個(gè)參數(shù)。第一個(gè)參數(shù)為調(diào)用createElementVNode函數(shù)生成input的vnode。第二個(gè)參數(shù)為傳入的自定義指令組成的數(shù)組,很明顯這里的二維數(shù)組的第一層只有一項(xiàng),說明只傳入了一個(gè)自定義指令。

回憶一下前面說的二維數(shù)組中的第二層的結(jié)構(gòu):?[Directive, value, argument, modifiers],第一個(gè)字段Directive表示這里傳入了一個(gè)名為vModelText的自定義指令,第二個(gè)字段value表示給vModelText指令綁定的值為$setup.msg。我們?cè)?Vue 3 的 setup語法糖到底是什么東西?文章中已經(jīng)講過了,這里的$setup.msg實(shí)際就是指向的是setup中定義的名為msg的ref變量。

我們?cè)賮砜蠢锩娴?code>createElementVNode函數(shù),創(chuàng)建一個(gè)input的vnode。傳入了一個(gè)名為onUpdate:modelValue的props屬性,屬性值是一個(gè)經(jīng)過緩存的回調(diào)函數(shù)。

為什么需要緩存呢?因?yàn)槊看胃马撁娑紩?huì)執(zhí)行一次render函數(shù),每次執(zhí)行render函數(shù)都會(huì)調(diào)用一次createElementVNode函數(shù)。如果不緩存那不就變成了每次更新頁面都會(huì)生成一個(gè)onUpdate:modelValue的回調(diào)函數(shù)。這里的回調(diào)函數(shù)也很簡單,接收一個(gè)$event變量。這個(gè)$event變量就是輸入框中輸入的值,然后最新的輸入框中的值同步到setup中的msg變量。

總結(jié)一下就是給input標(biāo)簽的vnode添加了一個(gè)vModelText的自定義指令,并且給指令綁定的值為msg變量。還有就是在input標(biāo)簽的vnode中添加了一個(gè)onUpdate:modelValue的屬性,屬性值是一個(gè)回調(diào)函數(shù),觸發(fā)這個(gè)回調(diào)函數(shù)就會(huì)將msg變量的值更新為輸入框中的最新值。我們知道input輸入框中的值對(duì)應(yīng)的是value屬性,監(jiān)聽的是input和change事件。那么這里有兩個(gè)問題:

  • 如何將vModelText自定義指令綁定的msg變量的值傳遞給input輸入框中的value屬性的呢?

  • input標(biāo)簽監(jiān)聽input和change事件,編譯后input上面卻是一個(gè)名為onUpdate:modelValue的props回調(diào)函數(shù)?

要回答上面的兩個(gè)問題我們需要看vModelText自定義指令是什么樣的。

vModelText自定義指令

vModelText是一個(gè)運(yùn)行時(shí)的v-model指令,為什么說是運(yùn)行時(shí)呢? 面試官:只知道v-model是modelValue語法糖,那你可以走了 文章中我們已經(jīng)講過了,在編譯時(shí)就會(huì)將組件上面的v-model指令編譯成modelValue屬性和@update:modelValue事件。所以當(dāng)運(yùn)行時(shí)在組件上已經(jīng)沒有了v-model指令了,只有原生input在運(yùn)行時(shí)依然還有v-model指令,也就是vModelText自定義指令。

我們來看看vModelText自定義指令的代碼:

const vModelText = {
  created(el, { modifiers: { lazy, trim, number } }, vnode) {
    // ...
  },
  mounted(el, { value }) {
    // ...
  },
  beforeUpdate(el, { value, modifiers: { lazy, trim, number } }, vnode) {
    // ...
  },
}

從上面可以看到vModelText自定義指令中使用了三個(gè)鉤子函數(shù):createdmounted、beforeUpdate,我們來看看上面三個(gè)鉤子函數(shù)中使用到的參數(shù):

  • el:指令綁定到的元素。這可以用于直接操作 DOM。

  • binding:一個(gè)對(duì)象,包含以下屬性。上面的例子中是直接解構(gòu)了binding對(duì)象。

    • value:傳遞給指令的值。例如在?v-model="msg"?中,其中msg變量的值為“hello word”,value的值就是“hello word”。

    • modifiers:一個(gè)包含修飾符的對(duì)象,v-model支持lazy, trim, number這三個(gè)修飾符。

      • lazy:默認(rèn)情況下,v-model?會(huì)在每次?input?事件后更新數(shù)據(jù)。你可以添加?lazy?修飾符來改為在每次?change?事件后更新數(shù)據(jù),在input輸入框中就是失去焦點(diǎn)時(shí)再更新數(shù)據(jù)。

      • trim:去除用戶輸入內(nèi)容中兩端的空格。

      • number:讓用戶輸入自動(dòng)轉(zhuǎn)換為數(shù)字。

  • vnode:綁定元素的 VNode(虛擬DOM)。

mounted鉤子函數(shù)

我們先來看mounted鉤子函數(shù),代碼如下:

const vModelText = {
  mounted(el, { value }) {
    el.value = value == null ? "" : value;
  },
}

mounted中的代碼很簡單,在mounted時(shí)如果v-model綁定的msg變量的值不為空,那么就將msg變量的值同步到input輸入框中。

created鉤子函數(shù)

我們接著來看created鉤子函數(shù)中的代碼,如下:

const assignKey = Symbol("_assign");
const vModelText = {
  created(el, { modifiers: { lazy, trim, number } }, vnode) {
    el[assignKey] = getModelAssigner(vnode);
    const castToNumber =
      number || (vnode.props && vnode.props.type === "number");
    addEventListener(el, lazy ? "change" : "input", (e) => {
      if (e.target.composing) return;
      let domValue = el.value;
      if (trim) {
        domValue = domValue.trim();
      }
      if (castToNumber) {
        domValue = looseToNumber(domValue);
      }
      el[assignKey](domValue);
    });
    if (trim) {
      addEventListener(el, "change", () => {
        el.value = el.value.trim();
      });
    }
    if (!lazy) {
      addEventListener(el, "compositionstart", onCompositionStart);
      addEventListener(el, "compositionend", onCompositionEnd);
    }
  },
}

created鉤子函數(shù)中的代碼主要分為五部分。

第一部分

首先我們來看第一部分代碼:

el[assignKey] = getModelAssigner(vnode);

我們先來看這個(gè)getModelAssigner函數(shù)。代碼如下:

const getModelAssigner = (vnode) => {
const fn = vnode.props["onUpdate:modelValue"];
return isArray(fn) ? (value) => invokeArrayFns(fn, value) : fn;
};

getModelAssigner函數(shù)的代碼很簡單,就是返回vnode上面名為onUpdate:modelValue的props回調(diào)函數(shù)。前面我們已經(jīng)講過了執(zhí)行這個(gè)回調(diào)函數(shù)會(huì)同步更新v-model綁定的msg變量。

所以第一部分代碼的作用就是取出input標(biāo)簽上面名為onUpdate:modelValue的props回調(diào)函數(shù),然后賦值給input標(biāo)簽對(duì)象的assignKey方法上面,后面再輸入框中的input或者chang事件觸發(fā)時(shí)會(huì)手動(dòng)調(diào)用。這個(gè)assignKey是一個(gè)Symbol,唯一的標(biāo)識(shí)符。

第二部分

再來看第二部分代碼:

const castToNumber =
number || (vnode.props && vnode.props.type === "number");

castToNumber表示是否使用了.number修飾符,或者input輸入框上面是否有type=number的屬性。如果castToNumber的值為true,后續(xù)處理輸入框的值時(shí)會(huì)將其轉(zhuǎn)換成數(shù)字。

第三部分

我們接著來看第三部分的代碼:

addEventListener(el, lazy ? "change" : "input", (e) => {
if (e.target.composing) return;
let domValue = el.value;
if (trim) {
  domValue = domValue.trim();
}
if (castToNumber) {
  domValue = looseToNumber(domValue);
}
el[assignKey](domValue);
});

對(duì)input輸入框進(jìn)行事件監(jiān)聽,如果有.lazy修飾符就監(jiān)聽change事件,否則監(jiān)聽input事件??纯矗@不就和.lazy修飾符的作用對(duì)上了嘛。.lazy修飾符的作用是在每次change事件觸發(fā)時(shí)再去更新數(shù)據(jù)。
我們接著看里面的事件處理函數(shù),來看看第一行代碼:

if (e.target.composing) return;

當(dāng)用戶使用拼音輸入法輸入漢字時(shí),正在輸入拼音階段也會(huì)觸發(fā)input事件的。但是一般情況下我們只希望真正合成漢字時(shí)才觸發(fā)input去更新數(shù)據(jù),所以在輸入拼音階段觸發(fā)的input事件需要被return。至于e.target.composing什么時(shí)候被設(shè)置為true,什么時(shí)候又是false,我們接著會(huì)講。

后面的代碼就很簡單了,將輸入框中的值也就是el.value賦值給domValue變量。如果使用了.trim修飾符,就執(zhí)行trim方法,去除掉domValue變量中兩端的空格。

如果castToNumber的值為true,表示使用了.number修飾符或者在input上面使用了type=number。調(diào)用looseToNumber方法將domValue字符串轉(zhuǎn)換為數(shù)字。

最后將處理后的domValue,也就是處理后的輸入框中的輸入值,作為參數(shù)調(diào)用el[assignKey]方法。我們前面講過了el[assignKey]中存的就是input標(biāo)簽上面名為onUpdate:modelValue的props回調(diào)函數(shù),執(zhí)行el[assignKey]方法就是執(zhí)行回調(diào)函數(shù),在回調(diào)函數(shù)中會(huì)將v-model綁定的msg變量的值更新為處理后的輸入框中的輸入值。

現(xiàn)在你知道了為什么input標(biāo)簽監(jiān)聽input和change事件,編譯后input上面卻是一個(gè)名為onUpdate:modelValue的props回調(diào)函數(shù)了?

因?yàn)樵趇nput或者change事件的回調(diào)中會(huì)將輸入框的值根據(jù)傳入的修飾符進(jìn)行處理,然后將處理后的輸入框的值作為參數(shù)手動(dòng)調(diào)用onUpdate:modelValue回調(diào)函數(shù),在回調(diào)函數(shù)中更新綁定的msg變量。

第四部分

我們接著來看第四部分的代碼,如下:

if (trim) {
  addEventListener(el, "change", () => {
    el.value = el.value.trim();
  });
}

這一塊代碼很簡單,如果使用了.trim修飾符,觸發(fā)change事件,在input輸入框中就是失去焦點(diǎn)時(shí)。就會(huì)將輸入框中的值也trim一下,去掉前后的空格。

為什么需要有這塊代碼,前面在input或者change事件中不是已經(jīng)對(duì)輸入框中的值進(jìn)行trim處理了嗎?而且后面的beforeUpdate鉤子函數(shù)中也執(zhí)行了el.value = newValue將輸入框中的值更新為v-model綁定的msg變量的值。

答案是:前面確實(shí)對(duì)輸入框中拿到的值進(jìn)行trim處理,然后將trim處理后的值更新為v-model綁定的msg變量。但是我們并沒有將輸入框中的值更新為trim處理后的,雖然在beforeUpdate鉤子函數(shù)中會(huì)將輸入框中的值更新為v-model綁定的msg變量。但是如果只是在輸入框的前后輸入空格,那么經(jīng)過trim處理后在beforeUpdate鉤子函數(shù)中就會(huì)認(rèn)為輸入框中的值和msg變量的值相等。就不會(huì)執(zhí)行el.value = newValue,此時(shí)輸入框中的值還是有空格的,所以需要執(zhí)行第四部分的代碼將輸入框中的值替換為trim后的值。

第五部分

我們接著來看第五部分的代碼,如下:

if (!lazy) {
  addEventListener(el, "compositionstart", onCompositionStart);
  addEventListener(el, "compositionend", onCompositionEnd);
}

如果沒有使用.lazy修飾符,也就是在每次input時(shí)都會(huì)對(duì)綁定的變量進(jìn)行更新。

這里監(jiān)聽的compositionstart事件是:文本合成系統(tǒng)如開始新的輸入合成時(shí)會(huì)觸發(fā)?compositionstart?事件。舉個(gè)例子:當(dāng)用戶使用拼音輸入法開始輸入漢字時(shí),這個(gè)事件就會(huì)被觸發(fā)。

這里監(jiān)聽的compositionend事件是:當(dāng)文本段落的組成完成或取消時(shí),compositionend 事件將被觸發(fā)。舉個(gè)例子:當(dāng)用戶使用拼音輸入法,將輸入的拼音合成漢字時(shí),這個(gè)事件就會(huì)被觸發(fā)。

來看看onCompositionStart中的代碼,如下:

function onCompositionStart(e) {
  e.target.composing = true;
}

代碼很簡單,將e.target.composing設(shè)置為true。還記得我們前面在input輸入框的input或者change事件中會(huì)先去判斷這個(gè)e.target.composing,如果其為true,那么就return掉,這樣就不會(huì)在輸入拼音時(shí)也會(huì)更新v-model綁定的msg變量了。

我們來看看onCompositionEnd中的代碼,如下:

function onCompositionEnd(e) {
  const target = e.target;
  if (target.composing) {
    target.composing = false;
    target.dispatchEvent(new Event("input"));
  }
}

當(dāng)將拼音合成漢字時(shí)會(huì)將e.target.composing設(shè)置為false,這里為什么要調(diào)用target.dispatchEvent手動(dòng)觸發(fā)一個(gè)input事件呢?

答案是:將拼音合成漢字時(shí)input事件會(huì)比compositionend事件先觸發(fā),由于此時(shí)的e.target.composing的值還是true,所以input事件中后續(xù)的代碼就會(huì)被return。所以才需要將e.target.composing重置為false后,手動(dòng)觸發(fā)一個(gè)input事件,更新v-model綁定的msg變量。

beforeUpdate鉤子函數(shù)

我們接著來看看beforeUpdate鉤子函數(shù),會(huì)在每次因?yàn)轫憫?yīng)式狀態(tài)變更,導(dǎo)致頁面更新之前調(diào)用,代碼如下:

const vModelText = {
  beforeUpdate(el, { value, modifiers: { lazy, trim, number } }, vnode) {
    el[assignKey] = getModelAssigner(vnode);
    // avoid clearing unresolved text. #2302
    if (el.composing) return;

    const elValue =
      number || el.type === "number" ? looseToNumber(el.value) : el.value;
    const newValue = value == null ? "" : value;

    if (elValue === newValue) {
      return;
    }

    if (document.activeElement === el && el.type !== "range") {
      if (lazy) {
        return;
      }
      if (trim && el.value.trim() === newValue) {
        return;
      }
    }

    el.value = newValue;
  },
};

看完了前面的created函數(shù),再來看這個(gè)beforeUpdate函數(shù)就很簡單了。beforeUpdate鉤子函數(shù)最終要做的事情就是最后的這行代碼:

el.value = newValue;

這行代碼的意思是將輸入框中的值更新成v-model綁定的msg變量,為什么需要在beforeUpdate鉤子函數(shù)中執(zhí)行呢?

答案是msg是一個(gè)響應(yīng)式變量,如果在父組件上面因?yàn)槠渌蚋淖兞?code>msg變量的值后,這個(gè)時(shí)候就需要將input輸入框中的值同步更新為最新的msg變量。這也就解釋了我們前面的問題:如何將vModelText自定義指令綁定的msg變量的值傳遞給input輸入框中的value屬性的呢?

第一行代碼是:

el[assignKey] = getModelAssigner(vnode);

這里再次將vnode上面名為onUpdate:modelValue的props回調(diào)函數(shù)賦值給el[assignKey],之前在created的時(shí)候不是已經(jīng)賦值過一次了嗎,這里為什么會(huì)再次賦值呢?

答案是在有的場(chǎng)景中是不會(huì)緩存onUpdate:modelValue回調(diào)函數(shù),如果沒有緩存,那么每次執(zhí)行render函數(shù)都會(huì)生成新的onUpdate:modelValue回調(diào)函數(shù)。所以才需要在beforeUpdate鉤子函數(shù)中每次都將最新的onUpdate:modelValue回調(diào)函數(shù)賦值給el[assignKey],當(dāng)在input或者change事件觸發(fā)時(shí)執(zhí)行el[assignKey]的時(shí)候就是執(zhí)行的最新的onUpdate:modelValue回調(diào)函數(shù)。

再來看看第二行代碼,如下:

// avoid clearing unresolved text. #2302
if (el.composing) return;

這行代碼是為了修復(fù)bug:如果在輸入拼音的過程中,還沒有合成漢字之前。如果有其他的響應(yīng)式變量的值變化導(dǎo)致頁面刷新,這種時(shí)候就應(yīng)該return。否則由于此時(shí)的msg變量的值還是null,如果執(zhí)行el.value = newValue,輸入框中的輸入值就會(huì)被清空。詳情請(qǐng)查看issue: https://github.com/vuejs/core/issues/2302

后面的代碼就很簡單了,其中的document.activeElement屬性返回獲得當(dāng)前焦點(diǎn)(focus)的 DOM 元素,還有type = "range"我們平時(shí)基本不會(huì)使用。根據(jù)使用的修飾符拿到處理后的input輸入框中的值,然后和v-model綁定的msg變量進(jìn)行比較。如果兩者相等自然不需要執(zhí)行el.value = newValue將輸入框中的值更新為最新值。

總結(jié)

現(xiàn)在來看這個(gè)流程圖你應(yīng)該就很容易理解了:
面試官:在原生input上面使用v-model和組件上面使用有什么區(qū)別?
在組件上面使用v-model和原生input上面使用v-model區(qū)別主要有三點(diǎn):

  • 組件上面的v-model編譯后會(huì)生成modelValue屬性和@update:modelValue事件。

    而在原生input上面使用v-model編譯后不會(huì)生成modelValue屬性,只會(huì)生成onUpdate:modelValue回調(diào)函數(shù)和vModelText自定義指令。(在 面試官:只知道v-model是modelValue語法糖,那你可以走了 文章中我們已經(jīng)講過了@update:modelValue事件其實(shí)等價(jià)于onUpdate:modelValue回調(diào)函數(shù))

  • 在組件上面使用v-model,是由子組件中定義一個(gè)名為modelValue的props來接收父組件使用v-model綁定的變量,然后使用這個(gè)modelValue綁定到子組件的表單中。

    在原生input上面使用v-model,是由編譯后生成的vModelText自定義指令在mountedbeforeUpdate鉤子函數(shù)中去將v-model綁定的變量值更新到原生input輸入框的value屬性,以保證v-model綁定的變量值和input輸入框中的值始終一致。

  • 在組件上面使用v-model,是由子組件使用emit拋出@update:modelValue事件,在@update:modelValue的事件處理函數(shù)中去更新v-model綁定的變量。

    而在原生input上面使用v-model,是由編譯后生成的vModelText自定義指令在created鉤子函數(shù)中去監(jiān)聽原生input標(biāo)簽的input或者change事件。在事件回調(diào)函數(shù)中去手動(dòng)調(diào)用onUpdate:modelValue回調(diào)函數(shù),然后在回調(diào)函數(shù)中去更新v-model綁定的變量。

關(guān)注公眾號(hào):前端歐陽,解鎖我更多vue干貨文章。還可以加我微信,私信我想看哪些vue原理文章,我會(huì)根據(jù)大家的反饋進(jìn)行創(chuàng)作。
面試官:在原生input上面使用v-model和組件上面使用有什么區(qū)別?文章來源地址http://www.zghlxwxcb.cn/news/detail-856576.html

到了這里,關(guān)于面試官:在原生input上面使用v-model和組件上面使用有什么區(qū)別?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue3-在HTML標(biāo)簽、組件標(biāo)簽上使用v-model

    本篇為Vue3學(xué)習(xí)中遇到的v-model相關(guān)的記錄,如有問題歡迎指正 v-model通常在input、select等標(biāo)簽上來實(shí)現(xiàn)數(shù)據(jù)雙向綁定 原理 :v-model通過給標(biāo)簽value賦值來實(shí)現(xiàn)? 數(shù)據(jù)—頁面 的綁定。然后通過綁定input事件實(shí)現(xiàn) 頁面—數(shù)據(jù) 的綁定。 原理 :在組件上時(shí),v-model通過 :modelValue 來進(jìn)行

    2024年01月24日
    瀏覽(25)
  • 【vue2第十一章】v-model的原理詳解 與 如何使用v-model對(duì)父子組件的value綁定 和修飾符.sync

    【vue2第十一章】v-model的原理詳解 與 如何使用v-model對(duì)父子組件的value綁定 和修飾符.sync

    v-model的原理詳解 v-model的本質(zhì)就是一個(gè)語法糖,實(shí)際上就是 :value=\\\"msg\\\" 與 @input=\\\"msg = $event.target.value\\\" 的簡寫。 :value=\\\"msg\\\" 從數(shù)據(jù)單向綁定到input框,當(dāng)data數(shù)據(jù)中的msg內(nèi)容一旦改變,而input框數(shù)據(jù)也隨之改變。 @input=\\\"msg = $event.target.value\\\" 是為input框綁定了input事件,內(nèi)容改變則觸發(fā)

    2024年02月10日
    瀏覽(20)
  • uni-app 使用v-model封裝picker組件和自定義樣式

    1、v-model封裝picker組件 (1)封裝組件myPicker.vue (2)組件調(diào)用 (3)屬性說明 屬性名 類型 默認(rèn)值 說明 options Object 數(shù)據(jù)選項(xiàng),默認(rèn)[{ name: \\\"辦公\\\", value: \\\"1\\\" }]格式 rangeKey String label 數(shù)據(jù)選項(xiàng)的屬性名 rangeValue String value 數(shù)據(jù)選項(xiàng)的屬性值 placeholoder String 請(qǐng)選擇 未選擇數(shù)據(jù)時(shí)的默認(rèn)

    2024年02月09日
    瀏覽(28)
  • 父組件明明使用了v-model,子組件竟然可以不用定義props和emit拋出事件,快來看看吧

    父組件明明使用了v-model,子組件竟然可以不用定義props和emit拋出事件,快來看看吧

    vue3.4增加了 defineModel 宏函數(shù),在子組件內(nèi)修改了 defineModel 的返回值,父組件上 v-model 綁定的變量就會(huì)被更新。大家都知道 v-model 是 :modelValue 和 @update:modelValue 的語法糖,但是你知道為什么我們?cè)谧咏M件內(nèi)沒有寫任何關(guān)于 props 的定義和 emit 事件觸發(fā)的代碼嗎?還有在 template

    2024年04月08日
    瀏覽(25)
  • element ui input 深層循環(huán)v-model綁定默認(rèn)數(shù)據(jù)刪除不了的情況

    例子: 在項(xiàng)目開發(fā)中遇到的,簡單記錄一下? 給input一個(gè)@input方法? 使其更新視圖,這樣子就可以正常編輯刪除了 出現(xiàn)這種情況是vue不能檢測(cè)到對(duì)象屬性的添加或者刪除導(dǎo)致視圖無法更新

    2024年02月15日
    瀏覽(35)
  • 【Vue技巧】Vue2和Vue3組件上使用v-model的實(shí)現(xiàn)原理

    ChatGPT4.0國內(nèi)站點(diǎn),支持GPT4 Vision 視覺模型:海鯨AI 在Vue中, v-model 是一個(gè)語法糖,用于在輸入框、選擇框等表單元素上創(chuàng)建雙向數(shù)據(jù)綁定。當(dāng)你在自定義組件中實(shí)現(xiàn) v-model 功能時(shí),你需要理解它背后的原理: v-model 實(shí)際上是一個(gè)屬性和一個(gè)事件的簡寫。 在 Vue 2.x 中, v-mode

    2024年01月15日
    瀏覽(29)
  • vue項(xiàng)目中對(duì)組件使用v-model綁定值,在vue3中如何更新數(shù)據(jù)

    vue項(xiàng)目中對(duì)組件使用v-model綁定值,在vue3中如何更新數(shù)據(jù)

    在el-form 中 el-form-item 綁定組件進(jìn)行校驗(yàn) 想在表單下面爆紅提示 可以對(duì)組件使用v-model綁定值 vue2 通過this.$emit(‘input’,value) 更新 v-model值 vue3 通過this.$emit(‘update:modelValue’ ,value) 更新 v-model值

    2024年02月15日
    瀏覽(20)
  • 組件v-model

    最近看到vue版本更新到3.4.x了,其中有個(gè)defineModel API,defineModel在3.3的時(shí)候是作為實(shí)驗(yàn)特性發(fā)布的,在3.4中逐漸穩(wěn)定。這個(gè)API就是Vue3簡化組件v-model的寫法的,所以這篇就一塊兒來總結(jié)一下vue中的組件v-model 官網(wǎng)的示例 ?先說下vue2中的使用,再說下vue3中的使用 下面這個(gè)單個(gè)v

    2024年02月01日
    瀏覽(17)
  • vue中內(nèi)置指令v-model的作用和常見使用方法介紹以及在自定義組件上支持

    vue中內(nèi)置指令v-model的作用和常見使用方法介紹以及在自定義組件上支持

    一、v-model是什么 v-model是Vue框架的一種內(nèi)置的API指令,本質(zhì)是一種語法糖寫法,它負(fù)責(zé)監(jiān)聽用戶的輸入事件以更新數(shù)據(jù),并對(duì)一些極端場(chǎng)景進(jìn)行一些特殊處理。在Vue中,v-model是用于在表單元素和組件之間創(chuàng)建雙向數(shù)據(jù)綁定的指令。它可以簡化表單元素的綁定,使得在用戶輸入

    2024年01月19日
    瀏覽(21)
  • vue父子組件傳值(v-model)

    子組件使用 props 接收父組件傳來的值 1)這里有個(gè)大坑, el-dialog 中一定要用 model-value 來代替 v-model ,不能用 v-model ,否則會(huì)報(bào)錯(cuò) (2)子組件中修改父組件傳入的參數(shù) visible 時(shí),使用 ??方式

    2024年02月11日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包