props/defineProps

props通过在子组件上绑定属性来实现父子组件之间的数据传递。父组件将数据作为prop传递给子组件,子组件在自己的作用域中可以访问和使用这些prop。

用法

子组件

//第一种
defineProps(["page"]);
//第二种
defineProps({
page:Number
});
//第三种
defineProps({
page:{
type:Number,
default:2
}
});
//第四种
defineProps:{
page:[String,Number]
}

若想在子组件内使用,可以用一个const常量接收defineProps的返回值,然后通过这个常量即可调用。

父组件

使用:来传递值

示例

子组件

<template>
<h1>子组件</h1>
<ul class="list">
<li class="list-item"
v-for="(item, index) in props.msg" :key="index">
{{ item }}
</li>
</ul>
</template>

<script setup>
const props = defineProps({
msg: {
type: Array,
default: () => []
}
})
</script>

父组件

<template>
<h1>父组件</h1>
<div class="input-group">
<input type="text" v-model="val">
<button @click="handle">发送数据</button>
</div>
<Child :msg="list"/>
</template>

<script setup>
import { ref } from 'vue';
import Child from './components/Child1-1.vue';
const val = ref("");
const list = ref(['666']);
const handle = () => {
list.value.push(val.value);
}
</script>

效果

QQ截图20230608105029.jpg

emits/defineEmits

emits通过在子组件中声明可触发的事件,使得子组件可以在适当的时机触发这些事件。父组件可以在子组件上监听这些事件,并在触发时执行相应的处理逻辑。

用法

父组件

使用@传递方法以监听

子组件

首先声明一个变量emits来接收父组件的方法,然后在子组件内需要触发父组件方法的函数内使用emits即可。

const emits = defineEmits(['add'])  //定义一个变量来接收父组件的方法
const handle = () => {
emits('add', val.value)
}
<button @click="handle">发送数据</button>

示例

父组件

<template>
<Child @add="handleAdd"/>
<h1>父组件</h1>
<ul class="list">
<li class="list-item"
v-for="(item, index) in list" :key="index">
{{ item }}
</li>
</ul>
</template>

<script setup>
import { ref } from 'vue';
import Child from './components/Child2-1.vue';
const list = ref(['默认测试数据'])
const handleAdd = (val) => {
list.value.push(val);
}
</script>

子组件

<template>
<h1>子组件</h1>
<div class="input-group">
<input type="text" v-model="val">
<button @click="handle">发送数据</button>
</div>
</template>

<script setup>
import { ref } from 'vue';
const val = ref("");
const emits = defineEmits(['add']) //定义一个变量来接收父组件传来的方法
const handle = () => {
emits('add', val.value)
}
</script>

效果

Dingtalk_20230608124512.jpg

ref/defineExpose

通过使用ref将数据或方法包装,并使用defineExpose将其暴露给父组件。父组件可以通过在子组件上使用ref来访问这些暴露出来的数据或方法。这种方式使得父组件可以直接访问和操作子组件的内部状态。

definePropsdefineEmits一样,defineExpose也是内置的,不需要import,不过definePropsdefineEmits都会返回一个实例,而defineExpose是没有返回值的,而且要在方法声明定义以后使用。

用法

子组件

defineExpose({
暴露给父组件的变量名:子组件内变量
})

父组件

首先使用ref包装子组件<Child ref="childRef"/>,然后通过ref调用子组件暴露的变量即可。

示例

子组件

<template>
<h1>子组件</h1>
<div class="input-group">
<input type="text" v-model="val">
<button @click="handle">添加</button>
</div>
</template>

<script setup>
import { ref } from 'vue';
const val = ref('')
const list = ref(['默认测试数据!'])
const handle = () => {
list.value.push(val.value);
}
defineExpose({msg:list})
</script>

父组件

template内使用:

<template>
<Child ref="childRef"/>
<h1>父组件</h1>
<ul class="list">
<li class="list-item"
v-for="(item, index) in childRef?.msg" :key="index">
{{ item }}
</li>
</ul>
</template>

<script setup>
import { ref } from 'vue';
import Child from './components/Child4.vue';
const childRef = ref("");
</script>

childRef?.msg这里的问号是等childRef数据加载完毕后才去取数据,否则这里可能取不到值,这里需要考虑到父组件和子组件的生命周期。

在script内使用:

const formDialogRef = ref(AddressFormDialog)

const openDialog=(mode)=>{
if (!formDialogRef.value) return
formDialogRef.value.openDialog(mode)
}

v-model

v-model是通过将属性和事件绑定到同一个值来实现双向数据绑定。相当于父组件将自己的数据源交给子组件处理,父组件里不需要写什么代码,操作大都放到子组件里去写。

示例

父组件

<template>
<Child v-model:msg="list"/>
<h1>父组件</h1>
<ul class="list">
<li class="list-item"
v-for="(item, index) in list"
:key="index">
{{ item }}
</li>
</ul>
</template>

<script setup>
import { ref } from 'vue';
import Child from './components/Child3.vue';
const list = ref(['默认测试数据!'])
</script>

子组件

<template>
<h1>子组件</h1>
<div class="input-group">
<input type="text" v-model="val">
<button @click="handle">添加</button>
</div>
</template>

<script setup>
import { ref } from 'vue';
const props = defineProps({
msg:Array
})
const val = ref('')
const emits = defineEmits(['update:msg'])
const handle = () => {
const arr = props.msg;
arr.push(val.value);
emits('update:msg', arr);
}
</script>

attrs

attrs用于子组件接收父组件中不是通过props接收的属性。父组件给子组件传递属性,可以是自定义属性,这对于在子组件中将额外的prop传递给子元素或子组件比较有用。

示例

父组件

<template>
<h1>父组件 传送数据</h1>
<Child :fruit="data1" :type="data2"/>
</template>

<script setup>
import { ref } from 'vue';
import Child from './components/Child6.vue';
const data1 = ref("水果");
const data2 = ref("哈密瓜");
</script>

子组件

<template>
<h1>子组件 接收数据</h1>
<p>子组件通过props收到的是: {{props.fruit}}</p>
<p>子组件通过attrs收到的是: {{attrs.type}}</p>
</template>

<script setup>
import { useAttrs } from 'vue';
const props = defineProps({
fruit: {
type: String,
default: ""
}
})
const attrs = useAttrs();
console.log(attrs);
</script>

效果

QQ截图20230609115553.jpg

参考链接

vue3中父子传值 defineProps和defineEmits用法 - 掘金 (juejin.cn)

Vue父子组件通信的6种方式,props、emits、defineExpose、provide、attrs… - 掘金 (juejin.cn)

[Vue3] defineExpose用法 - 掘金 (juejin.cn)