日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

父組件使用v-model,子組件竟然不用定義props和emit拋出事件

來(lái)源: 責(zé)編: 時(shí)間:2024-04-08 08:59:54 245觀看
導(dǎo)讀前言vue3.4增加了defineModel宏函數(shù),在子組件內(nèi)修改了defineModel的返回值,父組件上v-model綁定的變量就會(huì)被更新。大家都知道v-model是:modelValue和@update:modelValue的語(yǔ)法糖,但是你知道為什么我們?cè)谧咏M件內(nèi)沒有寫

前言

vue3.4增加了defineModel宏函數(shù),在子組件內(nèi)修改了defineModel的返回值,父組件上v-model綁定的變量就會(huì)被更新。大家都知道v-model是:modelValue和@update:modelValue的語(yǔ)法糖,但是你知道為什么我們?cè)谧咏M件內(nèi)沒有寫任何關(guān)于props的定義和emit事件觸發(fā)的代碼嗎?還有在template渲染中defineModel的返回值等于父組件v-model綁定的變量值,那么這個(gè)返回值是否就是名為modelValue的props呢?直接修改defineModel的返回值就會(huì)修改父組件上面綁定的變量,那么這個(gè)行為是否相當(dāng)于子組件直接修改了父組件的變量值,破壞了vue的單向數(shù)據(jù)流呢?Ivc28資訊網(wǎng)——每日最新資訊28at.com

先說(shuō)答案

defineModel宏函數(shù)經(jīng)過(guò)編譯后會(huì)給vue組件對(duì)象上面增加modelValue的props選項(xiàng)和update:modelValue的emits選項(xiàng),執(zhí)行defineModel宏函數(shù)的代碼會(huì)變成執(zhí)行useModel函數(shù),如下圖:Ivc28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Ivc28資訊網(wǎng)——每日最新資訊28at.com

經(jīng)過(guò)編譯后defineModel宏函數(shù)已經(jīng)變成了useModel函數(shù),而useModel函數(shù)的返回值是一個(gè)ref對(duì)象。注意這個(gè)是ref對(duì)象不是props,所以我們才可以在組件內(nèi)直接修改defineModel的返回值。當(dāng)我們對(duì)這個(gè)ref對(duì)象進(jìn)行“讀操作”時(shí),會(huì)像Proxy一樣被攔截到ref對(duì)象的get方法。在get方法中會(huì)返回本地維護(hù)localValue變量,localValue變量依靠watchSyncEffect讓localValue變量始終和父組件傳遞的modelValue的props值一致。Ivc28資訊網(wǎng)——每日最新資訊28at.com

對(duì)返回值進(jìn)行“寫操作”會(huì)被攔截到ref對(duì)象的set方法中,在set方法中會(huì)將最新值同步到本地維護(hù)localValue變量,調(diào)用vue實(shí)例上的emit方法拋出update:modelValue事件給父組件,由父組件去更新父組件中v-model綁定的變量。如下圖:Ivc28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Ivc28資訊網(wǎng)——每日最新資訊28at.com

所以在子組件內(nèi)無(wú)需寫任何關(guān)于props的定義和emit事件觸發(fā)的代碼,因?yàn)樵诰幾gdefineModel宏函數(shù)的時(shí)候已經(jīng)幫我們生成了modelValue的props選項(xiàng)。在對(duì)返回的ref變量進(jìn)行寫操作時(shí)會(huì)觸發(fā)set方法,在set方法中會(huì)調(diào)用vue實(shí)例上的emit方法拋出update:modelValue事件給父組件。Ivc28資訊網(wǎng)——每日最新資訊28at.com

defineModel宏函數(shù)的返回值是一個(gè)ref變量,而不是一個(gè)props。所以我們可以直接修改defineModel宏函數(shù)的返回值,父組件綁定的變量之所以會(huì)改變是因?yàn)樵诘讓訒?huì)拋出update:modelValue事件給父組件,由父組件去更新綁定的變量,這一行為當(dāng)然滿足vue的單向數(shù)據(jù)流。Ivc28資訊網(wǎng)——每日最新資訊28at.com

什么是vue的單向數(shù)據(jù)流

vue的單向數(shù)據(jù)流是指,通過(guò)props將父組件的變量傳遞給子組件,在子組件中是沒有權(quán)限去修改父組件傳遞過(guò)來(lái)的變量。只能通過(guò)emit拋出事件給父組件,讓父組件在事件回調(diào)中去修改props傳遞的變量,然后通過(guò)props將更新后的變量傳遞給子組件。在這一過(guò)程中數(shù)據(jù)的流動(dòng)是單向的,由父組件傳遞給子組件,只有父組件有數(shù)據(jù)的更改權(quán),子組件不可直接更改數(shù)據(jù)。Ivc28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Ivc28資訊網(wǎng)——每日最新資訊28at.com

一個(gè)defineModel的例子

我在前面的 一文搞懂 Vue3 defineModel 雙向綁定:告別繁瑣代碼!文章中已經(jīng)講過(guò)了defineModel的各種用法,在這篇文章中我們就不多余贅述了。我們直接來(lái)看一個(gè)簡(jiǎn)單的defineModel的例子。Ivc28資訊網(wǎng)——每日最新資訊28at.com

下面這個(gè)是父組件的代碼:Ivc28資訊網(wǎng)——每日最新資訊28at.com

<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>

父組件的代碼很簡(jiǎn)單,使用v-model指令將inputValue變量傳遞給子組件。然后在父組件上使用p標(biāo)簽渲染出inputValue變量的值。Ivc28資訊網(wǎng)——每日最新資訊28at.com

我們接下來(lái)看子組件的代碼:Ivc28資訊網(wǎng)——每日最新資訊28at.com

<template>  <input v-model="model" />  <button @click="handelReset">reset</button></template><script setup lang="ts">const model = defineModel();function handelReset() {  model.value = "init";}</script>

子組件內(nèi)的代碼也很簡(jiǎn)單,將defineModel的返回值賦值給model變量。然后使用v-model指令將model變量綁定到子組件的input輸入框上面。并且還在按鈕的click事件時(shí)使用model.value = "init"將綁定的值重置為init字符串。請(qǐng)注意在子組件中我們沒有任何定義props的代碼,也沒有拋出emit事件的代碼。而是通過(guò)defineModel宏函數(shù)的返回值來(lái)接收父組件傳過(guò)來(lái)的名為modelValue的prop,并且在子組件中是直接通過(guò)給defineModel宏函數(shù)的返回值進(jìn)行賦值來(lái)修改父組件綁定的inputValue變量的值。Ivc28資訊網(wǎng)——每日最新資訊28at.com

defineModel編譯后的樣子

要回答前面提的幾個(gè)問(wèn)題,我們還是得從編譯后的子組件代碼說(shuō)起。下面這個(gè)是經(jīng)過(guò)簡(jiǎn)化編譯后的子組件代碼:Ivc28資訊網(wǎng)——每日最新資訊28at.com

import {  defineComponent as _defineComponent,  useModel as _useModel} from "/node_modules/.vite/deps/vue.js?v=23bfe016";const _sfc_main = _defineComponent({  __name: "child",  props: {    modelValue: {},    modelModifiers: {},  },  emits: ["update:modelValue"],  setup(__props) {    const model = _useModel(__props, "modelValue");    function handelReset() {      model.value = "init";    }    const __returned__ = { model, handelReset };    return __returned__;  },});function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {  return (    // ... 省略  );}_sfc_main.render = _sfc_render;export default _sfc_main;

從上面我們可以看到編譯后主要有_sfc_main和_sfc_render這兩塊,其中_sfc_render為render函數(shù),不是我們這篇文章關(guān)注的重點(diǎn)。我們來(lái)主要看_sfc_main對(duì)象,看這個(gè)對(duì)象的樣子有name、props、emits、setup屬性,我想你也能夠猜出來(lái)他就是vue的組件對(duì)象。從組件對(duì)象中我們可以看到已經(jīng)有了一個(gè)modelValue的props屬性,還有使用emits選項(xiàng)聲明了update:modelValue事件。我們?cè)谠创a中沒有任何地方有定義props和emits選項(xiàng),很明顯這兩個(gè)是通過(guò)編譯defineModel宏函數(shù)而來(lái)的。Ivc28資訊網(wǎng)——每日最新資訊28at.com

我們接著來(lái)看里面的setup函數(shù),可以看到經(jīng)過(guò)編譯后的setup函數(shù)中代碼和我們的源代碼很相似。只有defineModel不在了,取而代之的是一個(gè)useModel函數(shù)。Ivc28資訊網(wǎng)——每日最新資訊28at.com

// 編譯前的代碼const model = defineModel();// 編譯后的代碼const model = _useModel(__props, "modelValue");

還是同樣的套路,在瀏覽器的sources面板上面找到編譯后的js文件,然后給這個(gè)useModel打個(gè)斷點(diǎn)。至于如何找到編譯后的js文件我們?cè)谇懊娴奈恼轮幸呀?jīng)講了很多遍了,這里就不贅述了。刷新瀏覽器我們看到斷點(diǎn)已經(jīng)走到了使用useModel函數(shù)的地方,我們這里給useModel函數(shù)傳了兩個(gè)參數(shù)。第一個(gè)參數(shù)為子組件接收的props對(duì)象,第二個(gè)參數(shù)是寫死的字符串modelValue。進(jìn)入到useModel函數(shù)內(nèi)部,簡(jiǎn)化后的useModel函數(shù)是這樣的:Ivc28資訊網(wǎng)——每日最新資訊28at.com

function useModel(props, name) {  const i = getCurrentInstance();  const res = customRef((track2, trigger2) => {    watchSyncEffect(() => {      // 省略    });  });  return res;}

從上面的代碼中我們可以看到useModel中使用到的函數(shù)沒有一個(gè)是vue內(nèi)部源碼專用的函數(shù),全都是調(diào)用的vue暴露出來(lái)的API。這意味著我們可以參考defineModel的實(shí)現(xiàn)源碼,也就是useModel函數(shù),然后根據(jù)自己實(shí)際情況改良一個(gè)適合自己項(xiàng)目的defineModel函數(shù)。Ivc28資訊網(wǎng)——每日最新資訊28at.com

我們先來(lái)簡(jiǎn)單介紹一下useModel函數(shù)中使用到的API,分別是getCurrentInstance、customRef、watchSyncEffect,這三個(gè)API都是從vue中import導(dǎo)入的。Ivc28資訊網(wǎng)——每日最新資訊28at.com

getCurrentInstance函數(shù)

首先來(lái)看看getCurrentInstance函數(shù),他的作用是返回當(dāng)前的vue實(shí)例。為什么要調(diào)用這個(gè)函數(shù)呢?因?yàn)樵趕etup中this是拿不到vue實(shí)例的,后面對(duì)值進(jìn)行寫操作時(shí)會(huì)調(diào)用vue實(shí)例上面的emit方法拋出update事件。Ivc28資訊網(wǎng)——每日最新資訊28at.com

watchSyncEffect函數(shù)

接著我們來(lái)看watchSyncEffect函數(shù),這個(gè)API大家平時(shí)應(yīng)該比較熟悉了。他的作用是立即運(yùn)行一個(gè)函數(shù),同時(shí)響應(yīng)式地追蹤其依賴,并在依賴更改時(shí)立即重新執(zhí)行這個(gè)函數(shù)。Ivc28資訊網(wǎng)——每日最新資訊28at.com

比如下面這段代碼,會(huì)立即執(zhí)行console,當(dāng)count變量的值改變后,也會(huì)立即執(zhí)行console。Ivc28資訊網(wǎng)——每日最新資訊28at.com

const count = ref(0)watchSyncEffect(() => console.log(count.value))// -> 輸出 0

customRef函數(shù)

最后我們來(lái)看customRef函數(shù),他是useModel函數(shù)的核心。這個(gè)函數(shù)小伙伴們應(yīng)該用的比較少,我們這篇文章只簡(jiǎn)單講講他的用法即可。如果小伙伴們對(duì)customRef函數(shù)感興趣可以留言或者給我發(fā)消息,關(guān)注的小伙伴們多了我后面會(huì)安排一篇文章來(lái)專門講customRef函數(shù)。官方的解釋為:Ivc28資訊網(wǎng)——每日最新資訊28at.com

Ivc28資訊網(wǎng)——每日最新資訊28at.com

創(chuàng)建一個(gè)自定義的 ref,顯式聲明對(duì)其依賴追蹤和更新觸發(fā)的控制方式。customRef() 預(yù)期接收一個(gè)工廠函數(shù)作為參數(shù),這個(gè)工廠函數(shù)接受 track 和 trigger 兩個(gè)函數(shù)作為參數(shù),并返回一個(gè)帶有 get 和 set 方法的對(duì)象。Ivc28資訊網(wǎng)——每日最新資訊28at.com

這句話的意思是customRef函數(shù)的返回值是一個(gè)ref對(duì)象。當(dāng)我們對(duì)返回值ref對(duì)象進(jìn)行“讀操作”時(shí),會(huì)被攔截到ref對(duì)象的get方法中。當(dāng)我們對(duì)返回值ref對(duì)象進(jìn)行“寫操作”時(shí),會(huì)被攔截到ref對(duì)象的set方法中。和Promise相似同樣接收一個(gè)工廠函數(shù)作為參數(shù),Promise的工廠函數(shù)是接收的resolve和reject兩個(gè)函數(shù)作為參數(shù),customRef的工廠函數(shù)是接收的track和trigger兩個(gè)函數(shù)作為參數(shù)。track用于手動(dòng)進(jìn)行依賴收集,trigger函數(shù)用于手動(dòng)進(jìn)行依賴觸發(fā)。Ivc28資訊網(wǎng)——每日最新資訊28at.com

我們知道vue的響應(yīng)式原理是由依賴收集和依賴觸發(fā)的方式實(shí)現(xiàn)的,比如我們?cè)趖emplate中使用一個(gè)ref變量。當(dāng)template被編譯為render函數(shù)后,在瀏覽器中執(zhí)行render函數(shù)時(shí),就會(huì)對(duì)ref變量進(jìn)行讀操作。讀操作會(huì)被攔截到Proxy的get方法中,由于此時(shí)在執(zhí)行render函數(shù),所以當(dāng)前的依賴就是render函數(shù)。在get方法中會(huì)進(jìn)行依賴收集,將當(dāng)前的render函數(shù)作為依賴收集起來(lái)。注意這里的依賴收集是vue內(nèi)部自動(dòng)完成的,在我們的代碼中無(wú)需手動(dòng)去進(jìn)行依賴收集。Ivc28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)我們對(duì)ref變量進(jìn)行寫操作時(shí),此時(shí)會(huì)被攔截到Proxy的set方法,在set方法中會(huì)將收集到的依賴依次取出來(lái)執(zhí)行,我們前面收集的依賴是render函數(shù)。所以render函數(shù)就會(huì)重新執(zhí)行,執(zhí)行render函數(shù)生成虛擬DOM,再生成真實(shí)DOM,這樣瀏覽器中渲染的就是最新的ref變量的值。同樣這里依賴觸發(fā)也是在vue內(nèi)部自動(dòng)完成的,在我們的代碼中無(wú)需手動(dòng)去觸發(fā)依賴。Ivc28資訊網(wǎng)——每日最新資訊28at.com

搞清楚了依賴收集和依賴觸發(fā)現(xiàn)在來(lái)講track和trigger兩個(gè)函數(shù)你應(yīng)該就能很容易理解了,track和trigger兩個(gè)函數(shù)可以讓我們手動(dòng)控制什么時(shí)候進(jìn)行依賴收集和依賴觸發(fā)。執(zhí)行track函數(shù)就會(huì)手動(dòng)收集依賴,執(zhí)行trigger函數(shù)就會(huì)手動(dòng)觸發(fā)依賴,進(jìn)行頁(yè)面刷新。在defineModel這個(gè)場(chǎng)景中track手動(dòng)收集的依賴就是render函數(shù),trigger手動(dòng)觸發(fā)會(huì)導(dǎo)致render函數(shù)重新執(zhí)行,進(jìn)而完成頁(yè)面刷新。Ivc28資訊網(wǎng)——每日最新資訊28at.com

useModel函數(shù)

現(xiàn)在我們可以來(lái)看useModel函數(shù)了,簡(jiǎn)化后的代碼如下:Ivc28資訊網(wǎng)——每日最新資訊28at.com

function useModel(props, name) {  const i = getCurrentInstance();  const res = customRef((track2, trigger2) => {    let localValue;    watchSyncEffect(() => {      const propValue = props[name];      if (hasChanged(localValue, propValue)) {        localValue = propValue;        trigger2();      }    });    return {      get() {        track2();        return localValue;      },      set(value) {        if (hasChanged(value, localValue)) {          localValue = value;          trigger2();        }        i.emit(`update:${name}`, value);      },    };  });  return res;}

從上面我們可以看到useModel函數(shù)的代碼其實(shí)很簡(jiǎn)單,useModel的返回值就是customRef函數(shù)的返回值,也就是一個(gè)ref變量對(duì)象。我們看到返回值對(duì)象中有g(shù)et和set方法,還有在customRef函數(shù)中使用了watchSyncEffect函數(shù)。Ivc28資訊網(wǎng)——每日最新資訊28at.com

get方法

在前面的demo中,我們?cè)谧咏M件的template中使用v-model將defineModel的返回值綁定到一個(gè)input輸入框中。代碼如下:Ivc28資訊網(wǎng)——每日最新資訊28at.com

<input v-model="model" />

在第一次執(zhí)行render函數(shù)時(shí)會(huì)對(duì)model變量進(jìn)行讀操作,而model變量是defineModel宏函數(shù)的返回值。編譯后我們看到defineModel宏函數(shù)變成了useModel函數(shù)。所以對(duì)model變量進(jìn)行讀操作,其實(shí)就是對(duì)useModel函數(shù)的返回值進(jìn)行讀操作。我們看到useModel函數(shù)的返回值是一個(gè)自定義ref,在自定義ref中有g(shù)et和set方法,當(dāng)對(duì)自定義ref進(jìn)行讀操作時(shí)會(huì)被攔截到ref對(duì)象中的get方法。這里在get方法中會(huì)手動(dòng)執(zhí)行track2方法進(jìn)行依賴收集。因?yàn)榇藭r(shí)是在執(zhí)行render函數(shù),所以收集到的依賴就是render函數(shù),然后將本地維護(hù)的localValue的值進(jìn)行攔截返回。Ivc28資訊網(wǎng)——每日最新資訊28at.com

set方法

在我們前面的demo中,子組件reset按鈕的click事件中會(huì)對(duì)defineModel的返回值model變量進(jìn)行寫操作,代碼如下:Ivc28資訊網(wǎng)——每日最新資訊28at.com

function handelReset() {  model.value = "init";}

和對(duì)model變量“讀操作”同理,對(duì)model變量進(jìn)行“寫操作”也會(huì)被攔截到返回值ref對(duì)象的set方法中。在set方法中會(huì)先判斷新的值和本地維護(hù)的localValue的值比起來(lái)是否有修改。如果有修改那就將更新后的值同步更新到本地維護(hù)的localValue變量,這樣就保證了本地維護(hù)的localValue始終是最新的值。然后執(zhí)行trigger2函數(shù)手動(dòng)觸發(fā)收集的依賴,在前面get的時(shí)候收集的依賴是render函數(shù),所以這里觸發(fā)依賴會(huì)重新執(zhí)行render函數(shù),然后將最新的值渲染到瀏覽器上面。Ivc28資訊網(wǎng)——每日最新資訊28at.com

在set方法中接著會(huì)調(diào)用vue實(shí)例上面的emit方法進(jìn)行拋出事件,代碼如下:Ivc28資訊網(wǎng)——每日最新資訊28at.com

i.emit(`update:${name}`, value)

這里的i就是getCurrentInstance函數(shù)的返回值。前面我們講過(guò)了getCurrentInstance函數(shù)的返回值是當(dāng)前vue實(shí)例,所以這里就是調(diào)用vue實(shí)例上面的emit方法向父組件拋出事件。這里的name也就是調(diào)用useModel函數(shù)時(shí)傳入的第二個(gè)參數(shù),我們來(lái)回憶一下前面是怎樣調(diào)用useModel函數(shù)的 ,代碼如下:Ivc28資訊網(wǎng)——每日最新資訊28at.com

const model = _useModel(__props, "modelValue")

傳入的第一個(gè)參數(shù)為當(dāng)前的props對(duì)象,第二個(gè)參數(shù)是寫死的字符串"modelValue"。那這里調(diào)用emit拋出的事件就是update:modelValue,傳遞的參數(shù)為最新的value的值。這就是為什么不需要在子組件中使用使用emit拋出事件,因?yàn)樵赿efineModel宏函數(shù)編譯成的useModel函數(shù)中已經(jīng)幫我們使用emit拋出事件了。Ivc28資訊網(wǎng)——每日最新資訊28at.com

watchSyncEffect函數(shù)

我們接著來(lái)看子組件中怎么接收父組件傳遞過(guò)來(lái)的props呢,答案就在watchSyncEffect函數(shù)中。回憶一下前面講過(guò)的useModel函數(shù)中的watchSyncEffect代碼如下:Ivc28資訊網(wǎng)——每日最新資訊28at.com

function useModel(props, name) {  const res = customRef((track2, trigger2) => {    let localValue;    watchSyncEffect(() => {      const propValue = props[name];      if (hasChanged(localValue, propValue)) {        localValue = propValue;        trigger2();      }    });    return {     // ...省略    };  });  return res;}

這個(gè)name也就是調(diào)用useModel函數(shù)時(shí)傳過(guò)來(lái)的第二個(gè)參數(shù),我們前面已經(jīng)講過(guò)了是一個(gè)寫死的字符串"modelValue"。那這里的const propValue = props[name]就是取父組件傳遞過(guò)來(lái)的名為modelValue的prop,我們知道v-model就是:modelValue的語(yǔ)法糖,所以這個(gè)propValue就是取的是父組件v-model綁定的變量值。如果本地維護(hù)的localValue變量的值不等于父組件傳遞過(guò)來(lái)的值,那么就將本地維護(hù)的localValue變量更新,讓localValue變量始終和父組件傳遞過(guò)來(lái)的值一樣。并且觸發(fā)依賴重新執(zhí)行子組件的render函數(shù),將子組件的最新變量的值更新到瀏覽器中。為什么要調(diào)用trigger2函數(shù)呢?原因是可以在子組件的template中渲染defineModel函數(shù)的返回值,也就是父組件傳遞過(guò)來(lái)的prop變量。如果父組件傳遞過(guò)來(lái)的prop變量值改變后不重新調(diào)用trigger2函數(shù)以重新執(zhí)行render函數(shù),那么子組件中的渲染的變量值就一直都是舊的值了。因?yàn)檫@個(gè)是在watchSyncEffect內(nèi)執(zhí)行的,所以每次父組件傳過(guò)來(lái)的props值變化后都會(huì)再執(zhí)行一次,讓本地維護(hù)的localValue變量的值始終等于父組件傳遞過(guò)來(lái)的值,并且子組件頁(yè)面上也始終渲染的是最新的變量值。Ivc28資訊網(wǎng)——每日最新資訊28at.com

這就是為什么在子組件中沒有任何props定義了,因?yàn)樵赿efineModel宏函數(shù)編譯后會(huì)給vue組件對(duì)象塞一個(gè)modelValue的prop,并且在useModel函數(shù)中會(huì)維護(hù)一個(gè)名為localValue的本地變量接收父組件傳遞過(guò)來(lái)的props.modelValue,并且讓localValue變量和props.modelValue的值始終保持一致。Ivc28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)

現(xiàn)在我們可以回答前面提的幾個(gè)問(wèn)題了:Ivc28資訊網(wǎng)——每日最新資訊28at.com

  • 使用defineModel宏函數(shù)后,為什么我們?cè)谧咏M件內(nèi)沒有寫任何關(guān)于props定義的代碼?答案是本地會(huì)維護(hù)一個(gè)localValue變量接收父組件傳遞過(guò)來(lái)的名為modelValue的props。調(diào)用defineModel函數(shù)的代碼經(jīng)過(guò)編譯后會(huì)變成一個(gè)調(diào)用useModel函數(shù)的代碼,useModel函數(shù)的返回值是一個(gè)ref對(duì)象。當(dāng)我們對(duì)defineModel的返回值進(jìn)行“讀操作”時(shí),類似于Proxy的get方法一樣會(huì)對(duì)讀操作進(jìn)行攔截到返回值ref對(duì)象的get方法中。而get方法的返回值為本地維護(hù)的localValue變量,在watchSyncEffect的回調(diào)中將父組件傳遞過(guò)來(lái)的名為modelValue的props賦值給本地維護(hù)的localValue變量。并且由于是在watchSyncEffect中,所以每次props改變都會(huì)執(zhí)行這個(gè)回調(diào),所以本地維護(hù)的localValue變量始終是等于父組件傳遞過(guò)來(lái)的modelValue。也正是因?yàn)閐efineModel宏函數(shù)的返回值是一個(gè)ref對(duì)象而不是一個(gè)prop,所以我們可以在子組件內(nèi)直接將defineModel的返回值使用v-model綁定到子組件input輸入框上面。
  • 使用defineModel宏函數(shù)后,為什么我們?cè)谧咏M件內(nèi)沒有寫任何關(guān)于emit事件觸發(fā)的代碼?答案是因?yàn)檎{(diào)用defineModel函數(shù)的代碼經(jīng)過(guò)編譯后會(huì)變成一個(gè)調(diào)用useModel函數(shù)的代碼,useModel函數(shù)的返回值是一個(gè)ref對(duì)象。當(dāng)我們直接修改defineModel的返回值,也就是修改useModel函數(shù)的返回值。類似于Proxy的set方法一樣會(huì)對(duì)寫行為進(jìn)行攔截到ref對(duì)象中的set方法中。在set方法中會(huì)手動(dòng)觸發(fā)依賴,render函數(shù)就會(huì)重新執(zhí)行,瀏覽器上就會(huì)渲染最新的變量值。然后調(diào)用vue實(shí)例上的emit方法,向父組件拋出update:modelValue事件。并且將最新的值隨著事件一起傳遞給父組件,由父組件在update:modelValue事件回調(diào)中將父組件中v-model綁定的變量更新為最新值。
  • 在template渲染中defineModel的返回值等于父組件v-model綁定的變量值,那么這個(gè)返回值是否就是名為modelValue的props呢?從第一個(gè)回答中我們知道defineModel的返回值不是props,而是一個(gè)ref對(duì)象。
  • 直接修改defineModel的返回值就會(huì)修改父組件上面綁定的變量,那么這個(gè)行為是否相當(dāng)于子組件直接修改了父組件的變量值,破壞了vue的單向數(shù)據(jù)流呢?修改defineModel的返回值,就會(huì)更新父組件中v-model綁定的變量值。看著就像是子組件中直接修改了父組件的變量值,從表面上看著像是打破了vue的單向數(shù)據(jù)流。實(shí)則并不是那樣的,雖然我們?cè)诖a中沒有寫過(guò)emit拋出事件的代碼,但是在defineModel函數(shù)編譯成的useModel函數(shù)中已經(jīng)幫我們使用emit拋出事件了。所以并沒有打破vue的單向數(shù)據(jù)流

本文鏈接:http://m.www897cc.com/showinfo-26-81870-0.html父組件使用v-model,子組件竟然不用定義props和emit拋出事件

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 每天都提交代碼,那你知道.git目錄內(nèi)部的秘密嗎?

下一篇: promise(A).catch(f1).then(f2),f1執(zhí)行后f2會(huì)執(zhí)行嗎,為什么?

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
99热在线精品观看| 久久福利资源站| 亚洲电影免费在线观看| 亚洲国产另类久久久精品极度| 亚洲人成网站在线观看播放| 亚洲一区二区三区四区视频 | 欧美一区二区三区四区在线观看| 欧美一区二区三区男人的天堂 | 亚洲高清色综合| 亚洲最新中文字幕| 午夜精品久久久久久久蜜桃app| 久久成人av少妇免费| 欧美国产日韩在线| 国产欧美精品国产国产专区| 亚洲成人自拍视频| 亚洲专区在线| 美女脱光内衣内裤视频久久影院| 欧美日韩国产片| 国产综合色一区二区三区 | 乱码第一页成人| 国产精品成人观看视频免费| 国产视频一区二区在线观看| 亚洲精品美女91| 欧美一级视频一区二区| 嫩模写真一区二区三区三州| 国产精品久久久久久久久免费樱桃| 极品中文字幕一区| 亚洲午夜极品| 欧美成人一区二区三区在线观看| 国产精品日产欧美久久久久| 亚洲电影视频在线| 亚洲欧美日本伦理| 欧美精品 日韩| 精品成人一区| 午夜精品区一区二区三| 欧美精品一区二区三区在线看午夜| 国产视频综合在线| 一本色道久久综合| 美女脱光内衣内裤视频久久影院 | 日韩亚洲精品电影| 久久久久久久综合日本| 欧美四级在线观看| 91久久精品国产91性色 | 欧美系列精品| 亚洲激情精品| 久久久噜噜噜久久人人看| 欧美日韩综合视频| 亚洲激情二区| 久久久精品国产一区二区三区 | 欧美福利视频在线观看| 一区二区在线观看视频| 久久aⅴ国产紧身牛仔裤| 欧美视频免费| 亚洲精选一区二区| 免费欧美在线| 伊人久久婷婷| 欧美影院在线播放| 国产伦精品一区二区三区在线观看 | 99在线视频精品| 欧美国产日产韩国视频| 原创国产精品91| 久久精品系列| 国产一区二区精品久久91| 亚洲欧美在线一区| 欧美午夜视频网站| 一区二区国产日产| 欧美日韩国产成人| 最新国产の精品合集bt伙计| 噜噜噜在线观看免费视频日韩 | 一区二区三区.www| 欧美精品激情| 亚洲精品资源美女情侣酒店| 欧美成人dvd在线视频| 亚洲福利在线看| 老司机67194精品线观看| 韩国一区二区三区在线观看| 久久国产免费看| 国产一区二区中文| 久久精品综合一区| 尤物在线观看一区| 蜜臀av一级做a爰片久久| 亚洲福利视频网| 欧美成人免费网站| 亚洲精品日韩一| 欧美日韩成人精品| 一区二区精品在线观看| 欧美色综合天天久久综合精品| 99在线热播精品免费99热| 欧美日韩亚洲一区二| 亚洲视频国产视频| 欧美午夜在线| 午夜视频一区二区| 国产一区二区av| 久久影视精品| 亚洲区第一页| 欧美日韩一区二区三区免费看| 中文av字幕一区| 国产精品网站一区| 久久久久久久久一区二区| 在线欧美日韩精品| 欧美日本高清| 亚洲免费一级电影| 国产综合网站| 欧美成人综合| 亚洲手机在线| 国产亚洲午夜| 免费成人你懂的| 99pao成人国产永久免费视频| 欧美系列亚洲系列| 羞羞漫画18久久大片| 伊人精品视频| 欧美日韩高清一区| 亚洲欧美在线免费| 一区视频在线| 欧美日韩免费精品| 欧美在线一级视频| 亚洲国产一区二区三区青草影视| 欧美日韩国产区| 小嫩嫩精品导航| 亚洲高清成人| 国产精品vvv| 久久久久免费视频| 99国产精品| 国产日韩在线看片| 欧美电影资源| 午夜日韩视频| 亚洲国内在线| 国产精品福利网| 久久综合影音| 亚洲一二三四区| 影音先锋久久久| 国产精品久久久久永久免费观看 | 香港久久久电影| 亚洲国产日韩欧美一区二区三区| 国产精品yjizz| 久久久夜色精品亚洲| 日韩一区二区电影网| 国产亚洲成av人在线观看导航| 欧美福利电影在线观看| 午夜精品视频在线观看一区二区| 在线免费观看日韩欧美| 国产精品乱码妇女bbbb| 美女脱光内衣内裤视频久久网站| 亚洲伊人伊色伊影伊综合网| 一区精品在线| 国产精品日韩欧美一区二区三区| 美女尤物久久精品| 亚洲免费一级电影| 亚洲国产精品悠悠久久琪琪| 国产精品资源在线观看| 欧美日韩国产综合视频在线| 久久久综合激的五月天| 亚洲永久在线| 亚洲精品欧美日韩专区| 国产婷婷色综合av蜜臀av| 欧美日韩亚洲一区二区三区在线 | 午夜精品福利一区二区三区av| 亚洲国产99精品国自产| 国产美女精品免费电影| 欧美日本国产一区| 久久综合九色综合欧美就去吻| 亚洲免费影视| 在线视频精品一| 最新成人在线| 一区在线免费| 国产区二精品视| 欧美午夜免费影院| 欧美另类视频| 欧美成人69| 久久资源av| 欧美中在线观看| 亚洲欧美另类国产| 一本色道久久综合亚洲二区三区| 在线成人国产| 国产一区二区三区四区五区美女| 欧美性猛交视频| 欧美精品在线视频观看| 乱码第一页成人| 久久蜜桃精品| 欧美一区二区在线免费观看| 亚洲一区二区三区777| 亚洲美女在线观看| 亚洲欧洲久久| 亚洲激情在线观看视频免费| 伊人久久噜噜噜躁狠狠躁| 国产一区二区精品在线观看| 国产乱理伦片在线观看夜一区 | 国内精品久久久久久久影视蜜臀 | 亚洲视频欧美在线| 99国产精品久久久久久久| 亚洲高清三级视频| 在线播放中文一区| 精品51国产黑色丝袜高跟鞋| 国产一区二区成人| 国内激情久久| 精品成人免费| 在线观看亚洲视频啊啊啊啊| 精品av久久707| 在线国产日韩| 亚洲国产精品福利| 亚洲精品免费一二三区| 日韩视频―中文字幕| a91a精品视频在线观看| 一本一本久久a久久精品牛牛影视|