这也是面试经常问到的一道题,正好近期刷到这道题, 然后就写写小demo,顺便将父子组件通信
,兄弟组件通信
, 跨组件通信
, 总结复习一下.
1. props
1.1 props
的基本介绍:
- 定义
props
:在子组件中,你需要定义一个props
选项,列出你想要从父组件接收的所有属性。每个属性可以是一个字符串数组,或者是一个带有更多选项的对象,如类型type
、默认值default
和是否必须required
。 - 传递
props
:在父组件的模板中,你可以通过动态属性v-bind
或简写为:
来传递数据给子组件。 - 类型验证 :你可以为
props
指定期望的类型,例如String
、Number
、Array
、Object
等。如果传入的数据类型不匹配,Vue 将在浏览器控制台发出警告。 - 默认值 :可以为
props
提供一个默认值,如果父组件没有传递该属性,子组件将使用默认值。 - 必需性 :通过设置
required
为true
,你可以指定一个prop
是必需的。如果父组件没有传递这个必需的prop
,Vue 将在浏览器控制台发出警告。
1.2 示例
父组件
fater.vue
js
<template>
<!-- 也可以直接将数据传递给子组件 -->
<Child :user="user" :hobby="['篮球', '足球']" :iphone="123456789"></Child>
</template>
<script setup>
import { ref } from "vue"
import Child from "./components/child.vue";
// 可以在这里定义好数据, 上面指定
const user = {
name: '小明',
age: 18
}
</script>
子组件child.vue
js
<template>
<h2>我是子组件 child.vue</h2>
<h3>下方是接收来自父组件的数据</h3>
<div>
{{ user.name }}
</div>
<div>
{{ user.age }}
</div>
<ul>
<li v-for="item in hobby">{{ item }}</li>
</ul>
<div>手机号 {{ iphone }}</div>
</template>
<script setup>
import { ref } from "vue"
defineProps({
// 对象
user: {
type: Object,
required: true
},
// 数组
hobby: {
type: Array, // 类型
default: [], // 默认值
required: true // 必须,如果父组件不传入, 虽然不会导致报错, 但浏览器会有警告
},
// 字符串
iphone: {
type: String
}
});
</script>
页面效果
2. $emit
子组件将数据传递给父组件
2.1 emit
的基本用法:
- 注册事件 :在子组件中,你可以使用
defineEmits
函数来声明一个或多个自定义事件。 - 触发事件 :在子组件的逻辑中,你可以调用
emit
函数并传递事件名称和一个或多个参数。这些参数将被作为事件的数据传递给父组件。 - 监听事件 :父组件可以在模板中通过
v-on
或简写为@
来监听子组件触发的事件,并定义一个事件处理函数来接收这些数据。
2.2 代码示例
子组件 child.vue
js
<template>
<div>
<button @click="handleClick">发送给父组件数据</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
// 注册一个自定义事件名,向上传递时告诉父组件要触发的事件。
const emit = defineEmits(['changeMsg'])
// 定义好要传递给父组件的数据
const data = ref("这是子组件的数据")
function handleClick() {
// 注册事件名字 以及传递给父组件的参数
emit('changeMsg', data.value)
}
</script>
父组件 father.vue
js
<template>
<h1>来自子组件的数据:<span style="color: red;">{{ dataFromChild }}</span></h1>
<!-- 这里的自定义事件名字 需要和子组件注册的名字保持一致 -->
<Child @changeMsg="getDataFromChild" />
</template>
<script setup>
import { ref } from 'vue'
import Child from './components/child.vue'
const dataFromChild = ref("默认值")
const getDataFromChild = (data) => {
console.log(data); // 这里可以拿到子组件传过来的数据
dataFromChild.value = data // 将子组件拿到的数据 赋值给父组件的变量值
}
</script>
效果:
3. provide 提供 和 inject 注入
3.1 依赖注入基本介绍
一个父组件相对于其所有的后代组件,会作为依赖提供者 。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。 ---> 引自官方
provide()
函数接收两个参数。第一个参数被称为注入名 ,可以是一个字符串或是一个 Symbol
。后代组件会用注入名来查找期望注入的值。一个组件可以多次调用 provide()
,使用不同的注入名,注入不同的依赖值。
3.2 示例代码
父组件
js
<template>
<div>
<Child></Child>
<br>
<Child1></Child1>
</div>
</template>
<script setup>
import {ref,provide} from 'vue'
import Child from './components/child.vue';
import Child1 from './components/child1.vue';
// 可以提供多个值
provide('data',{
msg: ref('hello.this message from parent component'),
count: ref(0)
})
// 也可以提供单个值
provide("test","hello this is test")
</script>
子组件1
js
<template>
子组件2:这是来自父组件的数据 : <span style="color:red">{{ data.msg }}</span> count : {{ data.count }}
<br>
test:{{ test }}
</template>
<script setup>
import { ref, inject } from "vue"
// 父组件 使用inject 接收子组件provide 传递过来的数据
const data = inject('data')
const test = inject('test')
</script>
子组件2
js
<template>
子组件2:这是来自父组件的数据 : <span style="color:red">{{ data. msg}}</span> count : {{ data.count }}
<br>
test:{{ test }}
</template>
<script setup>
import { ref, inject } from "vue"
// 父组件 使用inject 接收子组件provide 传递过来的数据
const data = inject('data')
const test = inject('test')
</script>
解释:
父组件通过将自身的数据使用
provide
提供给所有子组件, 子组件可以使用inject
方法接收父组件向外提供的值. 注意 provide 和 inject 的注入名
需保持一致
, 这样才可以正常接收到数据
效果图:
4. ref 和 defineExpose
4.1 基本介绍
defineExpose
是一个在 <script setup>
中使用的 API,它允许组件显式地暴露其数据或方法,使得这些数据和方法可以在组件的外部被访问。
4.2 代码示例
子组件
我们通过
defineExpose
方法将子组件的变量 和 方法向外暴露
js
<template>
</template>
<script setup>
import { ref } from "vue"
const data = ref("我是子组件内部的数据")
const updataData = () => {
data.value = "更新子组件内部的数据"
}
// 将组件内部的一些函数或数据暴露给父组件
defineExpose({
data,
updataData
})
</script>
父组件
通过
ref
拿到子组件的实例
js
<template>
<div>
<Child ref="child" />
<button @click="updateMsg">更新子组件数据</button>
这是来自子组件的数据: <span style="color: red;">{{ mes }}</span>
</div>
</template>
<script setup>
import { ref,onMounted } from 'vue'
import Child from './components/child.vue'
// 通过ref 获取到子组件的实例
const child = ref(null)
const mes = ref("")
const updateMsg = () => {
child.value.updataData()
mes.value = child.value.data
}
onMounted(() => {
// 确保子组件已经挂载
if (child.value) {
console.log(child.value.data); // 访问子组件暴露的 data
mes.value = child.value.data
}
})
</script>
子组件的实例
效果:
调用子组件暴露的方法,父组件点击按钮之后, 执行子组件的那个更新数据的方法