Vu3.x如何给v-for循环出来的输入框绑定v-mode的值,以及实现父子组件传值、双向绑定

观前须知:本人演示使用的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 接受父组件传递过来的 textValupdate 函数,随后我们给输入框添加一个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),但是它们各自都实现了双向数据绑定以及数据监听,至此,效果实现,本博客仅用于开发过程中的记录以及复盘,仅供参考!

posted @ 2022-10-10 22:58  捡破烂的小z  阅读(1825)  评论(0编辑  收藏  举报