Vu3.x如何給v-for循環出來的輸入框綁定v-mode的值,以及實現父子組件傳值、雙向綁定

  • 2022 年 10 月 10 日
  • 筆記

觀前須知:本人演示使用的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),但是它們各自都實現了雙向數據綁定以及數據監聽,至此,效果實現,本部落格僅用於開發過程中的記錄以及復盤,僅供參考!

Tags: