代码源自尚硅谷最新课程
本人对Vue3的了解尚浅,很多知识停留在Vue2中,所以对Vue3中的V-model,很不了解
如有问题欢迎指正
首先的问题是,在Vue3中v-model 会自动将父组件的数据作为props传递给子组件props.
而子组件也可以通过definePropos接受数据就像一下代码中
<Child v-model="money"></Child> 对子组件Child 传递名为money的数据
let props = defineProps(["modelValue"]); 而子组件可以通过 defineProps接受数据
但是我在这里产生了一个疑问,为什么在父组件内v-model命名是money 但是接受名却是modelValue????
带着疑问我询问了chagpt
给出的答案如下
这是因为 v-model 在子组件上会自动将父组件的数据 model 转换为 modelValue prop 传递给子组件。也就是说,当你在父组件中使用 v-model 绑定子组件时,例如:
html <Child v-model="money" />v-model 会将 money 数据作为名为 modelValue 的 prop 传给 Child 组件。所以在子组件中,我们需要使用 modelValue 作为 props 选项的键来接收这个 prop:
js let props = defineProps(["modelValue"]);而不管父组件绑定时的数据 model 是什么名称,v-model 都会自动将其转换为 modelValue 传递给子组件。这么做的目的是让子组件可以和任何使用 v-model 绑定它的父组件通信,而不依赖具体的数据 model 是什么名称。如果 v-model 不做这个转换,那子组件就需要知道所有可能使用它的父组件的数据模型的名称,这显然是不现实的。所以,v-model 做了这一转换,让子组件只需要关心 modelValue 这个 prop,并通过它和任何父组件实现双向绑定通信。这里可能会产生一些疑问:如果多个父组件同时使用 v-model 绑定同一个子组件,那数据会有冲突吗?答案是不会的,因为 v-model 在每个父组件内部都创建单独的 prop 和事件:
这下我总算是明白了这个问题/
然后我又遇到了移一处不能理解的地方,就是v-model能绑定自定义事件还是啥????
<Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
后面我才知道
这段是通过v-mode传递给子组件pageNo和pageSize,再通过子组件内的
let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
来监听,并更新父组件数据
然后通过
<button @click="$emit('update:pageSize', pageSize + 4)">
<button @click="handler">pageNo{{ pageNo }}</button>
const handler = () => {
$emit("update:pageNo", props.pageNo + 3);
};
来触发事件
总结(狗头 不是自己写的:P):
1. v-model 可以在父子组件间创建双向绑定。父组件使用 v-model 绑定子组件时,Vue 会自动创建名为 modelValue 的 prop 传递给子组件,并监听子组件触发的 update:modelValue 事件更新父组件的数据。子组件需要定义接收 modelValue 的 props,并触发 update:modelValue 事件更新 prop。
2. defineProps 用于定义子组件接收的 props,defineEmits 定义子组件可以触发的事件。这有助于声明组件的 API,方便其他开发者理解。
3. 带有 update: 前缀的事件用于更新 prop。子组件触发 update:propName 事件,父组件就会更新传入的 propName prop。这是 Vue 组件实现双向绑定的一种设计模式。
4. 子组件不应该直接操作传入的 prop。更好的方式是:在子组件内部用 ref 或 reactive 管理数据,触发自定义事件时传入内部数据的最新值,父组件监听事件并更新 prop 同步最新值。这可以让子组件内部维护其状态与逻辑,父组件只负责同步。这符合组件的封装思想,可以构建出更加独立可靠的组件。
5. 自定义事件是子组件暴露给外部的一种通信方式。通过 emit 触发自定义事件,外部监听事件做出响应。这使得子组件具有了主动通知外部的能力。自定义事件应在 defineEmits 中定义,以声明组件 API 并获得在开发环境的警告功能。
这是父组件的源码
<template>
<div>
<h1>v-model:钱数{{ money }}{{pageNo}}{{pageSize}}</h1>
<input type="text" v-model="info" />
<hr />
<!-- props:父亲给儿子数据 -->
<!-- <Child :modelValue="money" @update:modelValue="handler"></Child> -->
<!--
v-model组件身上使用
第一:相当有给子组件传递props[modelValue] = 10000
第二:相当于给子组件绑定自定义事件update:modelValue
-->
<Child v-model="money"></Child>
<hr />
<Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
</div>
</template>
<script setup lang="ts">
//v-model指令:收集表单数据,数据双向绑定
//v-model也可以实现组件之间的通信,实现父子组件数据同步的业务
//父亲给子组件数据 props
//子组件给父组件数据 自定义事件
//引入子组件
import Child from "./Child.vue";
import Child1 from "./Child1.vue";
import { ref } from "vue";
let info = ref("");
//父组件的数据钱数
let money = ref(10000);
//自定义事件的回调
const handler = (num) => {
//将来接受子组件传递过来的数据
money.value = num;
};
//父亲的数据
let pageNo = ref(1);
let pageSize = ref(3);
</script>
接下来分别是子组件的源码
<template>
<div class="child">
<h3>钱数:{{ modelValue }}</h3>
<button @click="handler">父子组件数据同步</button>
</div>
</template>
<script setup lang="ts">
//接受props
let props = defineProps(["modelValue"]);
let $emit = defineEmits(['update:modelValue']);
//子组件内部按钮的点击回调
const handler = ()=>{
//触发自定义事件
$emit('update:modelValue',props.modelValue+1000);
}
</script>
<template>
<div class="child2">
<h1>同时绑定多个v-model</h1>
<button @click="handler">pageNo{{ pageNo }}</button>
<button @click="$emit('update:pageSize', pageSize + 4)">
pageSize{{ pageSize }}
</button>
</div>
</template>
<script setup lang="ts">
let props = defineProps(["pageNo", "pageSize"]);
let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
//第一个按钮的事件回调
const handler = () => {
$emit("update:pageNo", props.pageNo + 3);
};
</script>