Vue3中的常見組件通信之v-model使用詳解
Vue3中的常見組件通信之v-model
概述
? 在vue3中常見的組件通信有props、mitt、v-model、refs、parent、provide、inject、pinia、slot等。不同的組件關系用不同的傳遞方式。
常見的撘配形式如下表所示。
| 組件關系 | 傳遞方式 |
|---|---|
| 父傳子 | 1. props 2. v-model 3. $refs 4. 默認插槽、具名插槽 |
| 子傳父 | 1. props 2. 自定義事件 3. v-model 4. $parent 5. 作用域插槽 |
| 祖?zhèn)鲗O、孫傳祖 | 1. $attrs 2. provide、inject |
| 兄弟間、任意組件間 | 1. mitt 2. pinia |
? props和自定義事件詳見本人另一篇文章:
mitt用法詳見本人另一篇文章:
下面接著前面的文章繼續(xù)記錄v-model的用法。
v-model
v-model常用于普通html標簽中的雙向綁定,這個綁定用法無法實現跨組件通信,v-model用在組件標簽中的時候,可以實現父子間的組件通信,而這樣通信方式常用于UI組件庫。
要理解UI組件庫的v-model的雙向通信原理,需要先明白普通html標簽中的v-model的底層原理。
普通HTML標簽中v-model實現雙向綁定的底層原理
在普通html標簽中用v-model可以實現數據的雙向綁定,如下代碼所示是把input輸入框里的數據與username進行雙向綁定:
<template>
<div class="father">
<h3>父組件</h3>
<br>
<input id="input1" type="text" v-model="username">
</div>
</template>
<script setup lang="ts" name="Father">
import { ref } from "vue";
// 數據
let username = ref('zhansan')
</script>
<style scoped>
.father {
height: 300px;
padding: 20px;
color: #ffffff;
text-align:center;
background-image: url(https://xyyhxxx.oss-cn-beijing.aliyuncs.com/picGoImg/202406041301030.png);
background-size: cover
}
#input1{
color: #000;
}
</style>運行后在瀏覽器打開vue開發(fā)者工具,如下圖所示:

上圖中更改vue開發(fā)者工具中的username的值頁面也會跟著發(fā)生變化,這個實現的是把數據呈現在頁面,如果修改input輸入框中的內容,username的數據也會跟著發(fā)生改變,這個實現的是頁面?zhèn)飨驍祿?,這就雙向綁定中的雙向,而實現這個雙向綁定的關鍵就是在于input標簽中寫了v-model,如下所示:
<input id="input1" type="text" v-model="username">
而上面的代碼實現的底層原理是這樣的,先把上面的代碼改成如下圖所示:
<input id="input1" type="text" :value="username">
這樣可以實現數據呈現在頁面,數據修改頁面也會跟著修改,但是修改頁面,數據卻不會變化,這只實現了一個方向的數據綁定,接著再給input標簽增加屬性,如下代碼:
<input
id="input1"
type="text"
:value="username"
@input="username=$event.target.value"
>這樣再測試,就會發(fā)現頁面中的數據也可以傳向數據了,修改input標簽中的內容,數據也會變化。
注意上面代碼中@input="@input="username=event.target.value"這句代碼 ts 會報警,我們需要處理一下,對event.target進行斷言,報警就會消失:
<input
id="input1"
type="text"
:value="username"
@input="username=(<HTMLInputElement>$event.target).value"
>普通input標簽中v-model實現雙向綁定的底層原理就是:value+@input事件。
組件標簽中v-model中實現雙向綁定
首先準備一個自己的UI組件,作為子組件,代碼如下:
<template>
<input type="text">
</template>
<script setup lang="ts" name="MyInput">
</script>
<style scoped>
input{
background-color:transparent;
color: #ffffff;
border: 0px;
border-bottom: 1px solid #ffffff ;
margin: 5px;
}
</style>然后在父組件中引入:
//引入MyInput組件 import MyInput from "./MyInput.vue";
在父組件中把MyInput組件呈現在頁面中:
<label>用戶名:<MyInput/></label>
運行效果如下:

這樣效果出來了,但是沒有還沒有實現數據綁定,首先在MyInput組件標簽上增加:modelValue屬性和綁定@update:model-value事件,如下代碼:
<MyInput :modelValue="username" @update:model-value="username=$event"/>
然后需要在MyInput組件中聲明props和聲明事件來接收數據和事件:
//接收props defineProps(["modelValue"]) //聲明事件 let emit = defineEmits(['update:model-value'])
最后在MyInput組件中的普通html標簽中添加:value屬性和綁定@input事件:
<input
type="text"
:value="modelValue"
@input="emit('update:model-value',(<HTMLInputElement>$event.target).value)"
>至此,已經實現了父組件和子組件MyInput組件的雙向通信,如下圖所示:

最后在父組件中的MyInput組件標簽上可以直接簡寫為如下代碼:
<MyInput v-model="username"/>
實現的效果是完全一樣的。
我們在用UI組件庫的時候可以直接這樣寫,前提是UI組件庫已經處理好了底層邏輯。
以下是完整代碼:
- 父組件:
<template>
<div class="father">
<h3>父組件</h3>
<br>
<!-- <input id="input1" type="text" v-model="username"> -->
<!-- 下面是v-model 的本質 -->
<!-- <input
id="input1"
type="text"
:value="username"
@input="username=(<HTMLInputElement>$event.target).value"
> -->
<!-- 下面是v-model 的本質 -->
<!-- <label>用戶名:<MyInput :modelValue="username" @update:model-value="username=$event"/></label> -->
<label>用戶名:<MyInput v-model="username"/></label>
</div>
</template>
<script setup lang="ts" name="Father">
import { ref } from "vue";
//引入MyInput組件
import MyInput from "./MyInput.vue";
// 數據
let username = ref('zhansan')
</script>
<style scoped>
.father {
height: 300px;
padding: 20px;
color: #ffffff;
text-align:center;
background-image: url(https://xyyhxxx.oss-cn-beijing.aliyuncs.com/picGoImg/202406041301030.png);
background-size: cover
}
#input1{
color: #000;
}
</style>
- MyInput組件:
<template>
<input
type="text"
:value="modelValue"
@input="emit('update:model-value',(<HTMLInputElement>$event.target).value)"
>
</template>
<script setup lang="ts" name="MyInput">
//聲明props
defineProps(["modelValue"])
//聲明事件
let emit = defineEmits(['update:model-value'])
</script>
<style scoped>
input{
background-color:transparent;
color: #ffffff;
border: 0px;
border-bottom: 1px solid #ffffff ;
margin: 5px;
}
</style>一個UI組件實現多個數據傳送
在父組件中可以改value,比如改成usName,如下代碼所示:
<MyInput v-model:usName="username"/>
這個代碼的本質是如下代碼:
<MyInput :usName="username" @update:usName="username=$event"/>
在MyInput組件代碼中就需要改成如下代碼:
<template>
<input
type="text"
:value="usName"
@input="emit('update:usName',(<HTMLInputElement>$event.target).value)"
>
</template>
<script setup lang="ts" name="MyInput">
//聲明props
defineProps(["usName"])
//聲明事件
let emit = defineEmits(['update:usName'])
</script>這樣改完后運行效果跟之前是完全一樣的,接下來再擴展一下,父組件中的MyInput標簽改成如下代碼:
<MyInput v-model:usName="username" v-model:paword="password"/>
然后在MyInput組件中代碼改成如下:
<template>
<input
type="text"
:value="usName"
@input="emit('update:usName',(<HTMLInputElement>$event.target).value)"
>
<br>
<input
type="text"
:value="paword"
@input="emit('update:paword',(<HTMLInputElement>$event.target).value)"
>
</template>
<script setup lang="ts" name="MyInput">
//聲明props
defineProps(["usName",'paword'])
//聲明事件
let emit = defineEmits(['update:usName','update:paword'])
</script>這樣就實現一個組件內雙向綁定兩個數據了,如下圖所示:

總結
v-model可以實現父子間的通信,v-model即可以設置在普通html標簽中,也可以設置在組件標簽中,設置在組件標簽中可以實現父子間的雙向通信,前提是子組件底層做了處理。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
前端vue3中的ref與reactive用法及區(qū)別總結
這篇文章主要給大家介紹了關于前端vue3中的ref與reactive用法及區(qū)別的相關資料,關于ref及reactive的用法,還是要在開發(fā)中多多使用,遇到響應式失效問題,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-08-08
Vue 中v-model的完整用法及v-model的實現原理解析
這篇文章詳細介紹了Vue.js中的v-model指令的使用,包括基本用法、原理、結合不同類型的表單元素(如radio、checkbox、select)以及使用修飾符(如lazy、number、trim)等,感興趣的朋友一起看看吧2025-02-02
ant?菜單組件報錯Cannot?read?property?‘isRootMenu‘?of?undefin
這篇文章主要介紹了ant?菜單組件報錯Cannot?read?property?‘isRootMenu‘?of?undefined解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08

