觀前須知:本人演示使用的input是自己手敲的,如果使用的是element-ui等表單組建的input框請選擇性參考,不保證我的方法對你們也完全有效。
這裡我的MiniInput
是以元件形式引入的父頁面 (這裡只貼關鍵程式碼)
<template>
<div>
<MiniInput
v-for="item in titleArray"
:key="item.id"
>
<template #miniTitle> {{ item.name }} </template>
</MiniInput>
</div>
</template>
<script setup lang="ts">
import { Ref, ref } from 'vue'
import MiniInput from '../components/MiniInput.vue'
//用ref包裹陣列,方便後期實現雙向繫結
const titleArray: Ref<Array<TitleArray>> = ref([
{
name: 'Exclude content',
id: 1231,
textVal: ''
},
{
name: 'Federated content',
id: 1232,
textVal: ''
},
{
name: 'Optional retrieval',
id: 1233,
textVal: ''
},
])
</script>
<template>
<div class="from__input__mini">
<span class="mini-title">
<slot name="miniTitle"></slot>
</span>
<input class="mini-input" type="text" />
</div>
</template>
<script setup lang="ts">
</script>
上述程式碼可以得到以下介面效果,這是我們只完成了表面工作(請忽略樣式)
首先,我們要打通父子元件的隔閡,先將父元件的textVal傳遞給子元件,這裡我們需要使用到v-mode
語法,將我們先前定義好的陣列內的textVal屬性傳遞過去。
<!-- 下面新增了一行 v-mode -->
<MiniInput
v-model:textVal="item.textVal"
v-for="item in titleArray"
:key="item.id"
>
<template #miniTitle> {{ item.name }} </template>
</MiniInput>
隨後我們來到子元件,為接收父元件傳遞過來的值做準備
<script setup lang="ts">
// defineProps 用於接收父元件傳遞過來的引數
defineProps<{
textVal: string
}>()
</script>
此時我們就可以給子元件繫結父元件傳遞過來的引數了
<template>
<div class="from__input__mini">
<span class="mini-title">
<slot name="miniTitle"></slot>
</span>
<input :value="textVal" class="mini-input" type="text" />
</div>
</template>
<script setup lang="ts">
// defineProps 用於接收父元件傳遞過來的引數
defineProps<{
textVal: string
}>()
</script>
但是此時我們會發現,到目前為止我們也僅僅只是接受了父元件傳遞過來的引數,此時我們去輸入框改變內容時,並不會同時改變父元件中的值,那麼此時我們就要想辦法實現資料流的 雙向繫結
要實現雙向資料響應,首先子元件要使用 defineEmits
接受父元件傳遞過來的 textVal
的 update
函數,隨後我們給輸入框新增一個input事件,目的是監聽輸入內容隨後改變父元件中的對應屬性。
<template>
<div class="from__input__mini">
<span class="mini-title">
<slot name="miniTitle"></slot>
</span>
<input :value="textVal" @input="changeText" class="mini-input" type="text" />
</div>
</template>
<script setup lang="ts">
// defineProps 用於接收父元件傳遞過來的引數
defineProps<{
textVal: string
}>()
// 要實現雙向資料響應要使用 defineEmits 接受父元件傳遞過來的 textVal 的 update函數
const emit = defineEmits(['update:textVal'])
// 輸入框input事件
const changeText = (e: Event) => {
// 這裡因為ts自動型別推斷會把變數推斷為EventTarget,導致沒辦法讀取到.value屬性,所以要進行一個型別斷言
const target = e.target as HTMLInputElement
emit('update:textVal', target.value)
}
</script>
這時我們就可以回到父元件中,為父元件的陣列新增一個監聽事件:
// 這裡是父元件的script
<script setup lang="ts">
import { Ref, ref, watch } from 'vue'
...
...
...
// 監聽陣列
watch
titleArray,
() => {
console.log('陣列變化了')
},
{
deep: true
}
)
</script>
隨後進行測試
可以看到,雖然是通過迴圈生成的三個子元件(input),但是它們各自都實現了雙向資料繫結以及資料監聽,至此,效果實現,本部落格僅用於開發過程中的記錄以及覆盤,僅供參考!