Vue 3.4+ 中 defineModel 该如何正确使用呢?
在官网中查阅到了 defineModel
这个宏 API,于是就自己测试了一下,但是遇到一个很诡异的地方无法理解。
下面是测试代码:
这个是父组件,结构很简单,引入了一个子组件
<script lang="ts" setup>
import { ref, onBeforeUpdate, onUpdated } from "vue";
import Context from "../Context.vue";
const count = ref(100);
</script>
<template>
<Context v-model="count" />
</template>
子组件如下
<script lang="ts" setup>
import { ref, nextTick } from "vue";
const n = ref(0);
const count = defineModel({ type: Number, default: 13 });
count.value += 1;
count.value += 2;
count.value += 3;
count.value += 4;
console.log(count.value); // 这里为什么打印是 100?
nextTick(() => {
console.log(count.value); //这里结果为什么是 104??
});
</script>
<template>
<div> {{count}}</div>
</templage>
问题:子组件的输出是不是有点问题呢?
回复
1个回答
test
2024-06-18
众所周知,v-model
仅仅是语法糖,父组件中的 <Context v-model="count" />
将被编译为:
// 父组件
<Context
:modelValue="count"
@update:modelValue="$event => (count = $event)"
/>
那么子组件中的 defineModel
又是什么呢?从上面的代码中可以看出,它应该为子组件定义了一个包含 modelValue
的 props
和一个自定义事件 update:modelValue
。类似于:
// 子组件
const props = defineProps<{ modelValue: number }>(),
emit = defineEmits<{ 'update:modelValue': [value: number] }>()
同时它还有一个返回值,类型为 ModelRef
。它实际上也只是让我们使用更方便而包装的一层代理而已。当我们读取它的值时,它实际上是在访问 props.modelValue
;当我们设置它的值时,实际上也只是触发了 update:modelValue
事件而已:
const modelRef = {
get value() {
return props.modelValue
},
set value(newValue) {
emit('update:modelValue', newValue)
}
}
此时我们的应用中有两个 count
:
// 父组件
// Ref<number>
const count = ref(100)
// 子组件
// ModelRef<number>
const count = defineModel(/** code */)
一个是 Ref
,另一个是 ModelRef
。看上去似乎相同,实际上没有任何关系。他们之间实际上是通过父子组件间的 props
相联系起来的。
让我们回到问题,当子组件中执行 count.value += 1
时,发生了什么:
count.value += 1
==>
count.value = count.value + 1
==>
emit('update:modelValue', count.value + 1)
==>
emit('update:modelValue', props.modelValue + 1)
当执行完这一语句时,父组件中的 Ref
确实变成了 101,但是子组件的 props
的更新还要等到下一个 tick
,所以子组件中的 ModelRef
还是 100。
所以接下来 count.value += 2
、count.value += 3
、count.value += 4
将会分别把父组件的 Ref
设置为 102,103,104。
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容