vue3组件通信--v-model

130 阅读3分钟

v-model可以实现父子组件之间的通信,能实现父子组件之间数据同步的业务。

1.原始的写法

FatherComponent.vue组件:

<script setup>
import {ref} from "vue"
import ChildComponent from "@/components/ChildComponent.vue"

//父组件的数据,钱数
const money = ref(1000)

//自定义事件的回调
const handler = (value) => {
  console.log(value)
  money.value = value
}
</script>

<template>
  <div class="bg-blue h-75 w-100 ma-auto">
    <h1 class="text-center">我是父组件</h1>
    <h3>父组件的钱数:{{money}}块钱</h3>
    <ChildComponent :modelValue="money" @update:modelValue="handler" />
  </div>
</template>

这个部分可以这样写,这样就不需要定义回调函数了:
<ChildComponent :modelValue="money" @update:modelValue="$event=>(money=$event)" />

$event: 这是 Vue 中的事件对象。在这个特定的情况下,它是子组件通过 emit 触发的 modelValue 新值。
$event => (message = $event) : 这是一个箭头函数,它将 $event(即子组件传递的值)赋给父组件中的 message 变量。也可以理解为:

(event) => { message = event; }

上面代码中的:<ChildComponent :modelValue="money" @update:modelValue="handler" />,就是我们熟悉props子传父自定义事件子传父

  • :modelValue="money":是props父传子,把父亲的数据money传到子组件。
  • @update:modelValue="handler":自定义事件子传父,@update:modelValue是自定义事件(可能看着有点奇怪,但是必须就这么写!),handler是父组件内部的回调函数。

ChildComponent.vue组件:

<script setup>

//接受父组件给的数据
const props = defineProps(['modelValue'])

//接受父组件传递的自定义事件
const emit = defineEmits(['update:modelValue'])

//子组件内部的回调
const handler = () => {
  //触发自定义事件,把modelValue + 100传递给父组件
  emit('update:modelValue', props.modelValue + 100)
}
</script>

<template>
  <div class="bg-purple h-50 w-75 ma-auto">
    <h1 class="text-center">我是子组件</h1>
    <h3>父组件给的钱数:{{modelValue}}块钱</h3>

    <v-btn @click="handler" class="ml-6 bg-blue text-white">钱数+100</v-btn>
  </div>
</template>

在子组件内部,通过下面的函数:

//子组件内部的回调
const handler = () => {
  //触发自定义事件,把modelValue + 100传递给父组件
  emit('update:modelValue', props.modelValue + 100)
}

也可以更简化的写,这样就不用再定义一个回调函数了:

<v-btn @click="$emit('update:modelValue', modelValue + 100)" class="ml-6 bg-blue text-white">钱数+100</v-btn>

触发父亲传递的自定义函数,并且修改父亲给子组件传递的modelValue的值,并传递给父组件。
父组件内部通过下面的回调函数:

//自定义事件的回调
const handler = (value) => {
  console.log(value)
  money.value = value
}

更改自己的money
这样就可以父子组件之间的数据就是响应式的了。

image.png

2.简化写法

在子组件标签上写的这块儿代码,可以简化<ChildComponent :modelValue="money" @update:modelValue="handler" />
简化后: <ChildComponent v-model="money" />

下面是父组FatherComponent.vue件简化后的代码:

<script setup>
import {ref} from "vue"
import ChildComponent from "@/components/ChildComponent.vue"

//父组件的数据,钱数
const money = ref(1000)
</script>

<template>
  <div class="bg-blue h-75 w-100 ma-auto">
    <h1 class="text-center">我是父组件</h1>
    <h3>父组件的钱数:{{money}}块钱</h3>
    <ChildComponent v-model="money" />
  </div>
</template>

ChildComponent.vu的代码不用动:

<script setup>

//接受父组件给的数据
const props = defineProps(['modelValue'])

//接受父组件传递自定义事件
const emit = defineEmits(['update:modelValue'])

//子组件内部的回调
const handler = () => {
  //触发自定义事件,把modelValue + 100传递给父组件
  emit('update:modelValue', props.modelValue + 100)
}
</script>

<template>
  <div class="bg-purple h-50 w-75 ma-auto">
    <h1 class="text-center">我是子组件</h1>
    <h3>父组件给的钱数:{{modelValue}}块钱</h3>

    <v-btn @click="handler" class="ml-6 bg-blue text-white">钱数+100</v-btn>
  </div>
</template>

效果图:

image.png

3.使用最新的defineModel API

父组件:

<script setup>
import {ref} from "vue"
import ChildComponent from "./components/Child.vue"

//父组件的数据,钱数
const money = ref(1000)
</script>

<template>
  <div class="bg-blue h-75 w-100 ma-auto">
    <h1 class="text-center">我是父组件</h1>
    <h3>父组件的钱数:{{money}}块钱</h3>
    <ChildComponent v-model="money" />
  </div>
</template>

子组件:

<script setup>

// 使用最新的defineModel API
const money = defineModel()

const changeMoney = () => {
  money.value += 100
}
</script>

<template>
  <div class="bg-purple h-50 w-75 ma-auto">
    <h1 class="text-center">我是子组件</h1>
    <h3>父组件给的钱数:{{modelValue}}块钱</h3>

    <button @click="changeMoney" class="ml-6 bg-blue text-white">钱数+100</button>
  </div>
</template>

这个新的api从vue3.4开始可以使用,我个人感觉这个api非常好用。

image.png