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>
子组件的实例
效果:
调用子组件暴露的方法,父组件点击按钮之后, 执行子组件的那个更新数据的方法
5. pinia
5.1 介绍
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。
5.2 使用
安装pinia
shell
pnpm add pinia
第二步: 初始化pinia store
创建 Pinia Store
创建一个 userStore.js
文件,用来存放关于用户信息。一般都是在在 src/stores/
目录中.
初始化储存库代码
js
// 导入 defineStore 函数,这是创建 Pinia Store 的关键函数 import { defineStore } from 'pinia' // 使用 defineStore 函数创建一个名为 'user' 的 store // 这个 store 将包含用户的信息,如姓名、年龄和爱好 export const useUserStore = defineStore('user', { // state 函数返回一个对象,这个对象包含了该 store 的响应式状态 state: () => ({ name: "张三", // 用户的名字 age: 20, // 用户的年龄 hobby: ["吃饭", "睡觉", "打豆豆"], // 用户的爱好列表 }), // actions 对象包含了一系列可以修改 state 的方法 actions: { // setName 方法用于设置用户的姓名 setName(name) { this.name = name }, // setAge 方法用于设置用户的年龄 setAge(age) { this.age = age }, // setHobby 方法用于设置用户的爱好列表 setHobby(hobby) { this.hobby = hobby }, }, // getters 对象包含了一系列的计算属性,用于从 state 中派生出一些状态 getters: { // getHobby 函数是一个 getter,它返回 state 中的 hobby 状态 getHobby(state) { return state.hobby } } }) // 注意:在 Pinia 中,state 的修改是直接进行的,不需要像 Vuex 那样使用 mutations
在main.js入口文件注册Pinia
js
import './style.css' import { createApp } from 'vue' // 创建一个 pinia 实例 (根 store) 并将其传递给应用 + import { createPinia } from 'pinia' + const pinia = createPinia() import App from './App.vue' const app = createApp(App) + app.use(pinia) app.mount('#app')
其他组件使用useUserStore里面的数据
子组件
js
<template> <div style="width: 200px; height: 200px; background-color: pink;"> <h1>子组件</h1> 姓名: <span style="color:red">{{ userStore.name }}</span><br> 年龄: <span style="color:red">{{ userStore.age }}</span> </div> </template> <script setup> // 引入userStore import { useUserStore } from '../store/userStore' const userStore = useUserStore() </script>
父组件
js
<template> <div style="width: 500px; height: 500px; background-color: skyblue;"> <Child></Child> <h1>父组件 </h1> <li v-for="(item,index) in userUser.hobby" :key="index">{{ item }}</li> </div> </template> <script setup> import Child from './components/child.vue' import { useUserStore} from './store/userStore.js' const userUser = useUserStore() </script>
效果
6. mitt
6.1 介绍
Mitt 是一个简单、轻量级
的 JavaScript 事件发射器库
,它允许你在任何地方发布
和监听事件
,而无需关心对象之间的直接关系。Vue 3 不再内置事件总线(Event Bus),因此可以使用 Mitt 或其他类似库来实现组件间的通信。
6.2 使用
步骤 1: 安装 Mitt
首先,需要安装 Mitt。可以通过 npm 或 yarn 来安装:
sh
复制
csharp
npm install mitt # 或者 yarn add mitt # or pnpm add mitt
步骤 2: 创建 Mitt 实例
创建一个 Mitt 实例,在src
文件夹下创建utils
文件夹,然后在utils
文件夹下创建eventBus.js
文件,eventBus.js
文件内容如下:
js
// src/utils/eventBus.js import mitt from 'mitt' const emitter = mitt() export default emitter
步骤 3: 在组件中发布事件
在需要发布事件的组件中,导入 Mitt 实例并使用 emit
方法发布事件。
js
<template> <button @click="sendMessage">发送信息</button> </template> <script setup> import emitter from '../utils/eventBus.js' const data = { msg: '子组件的数据', count: 0, type: "success" } function sendMessage() { // 发布事件 emitter.emit('message', data) } </script>
步骤 4: 在其他组件中监听事件
在其他组件中,导入 Mitt 实例并使用 on
方法监听事件。
js
<template> <Child></Child> <p>{{ result.msg}}</p><br> <p>{{ result.count}}</p> <p>{{ result.type}}</p> </template> <script setup> import { ref, onMounted, onBeforeUnmount } from 'vue'; import emitter from './utils/eventBus' import Child from './components/child.vue'; const result = ref({}) onMounted(() => { emitter.on('message', (data) => { console.log('message', data); result.value = data }) }) onBeforeUnmount(() => { emitter.off('message') }) </script>
当我们点击发布事件的那个按钮,就会成功发布一个名为
message
的事件,然后在其他组件里面使用on
进行监听该事件.
6.3 效果
7. 结语
通过这次的demo练习, 对于不同的情况组件通信的方式有了更全面的认识.我们在日常开发当中, 需根据具体情况,选择对应的通信方案.