总结vue3中常用的组件间通信的方法

简介: 总结vue3中常用的组件间通信的方法


1.1 props 的基本介绍:

  1. 定义 props:在子组件中,你需要定义一个 props 选项,列出你想要从父组件接收的所有属性。每个属性可以是一个字符串数组,或者是一个带有更多选项的对象,如类型 type、默认值 default 和是否必须 required
  2. 传递 props:在父组件的模板中,你可以通过动态属性 v-bind 或简写为 : 来传递数据给子组件。
  3. 类型验证:你可以为 props 指定期望的类型,例如 StringNumberArrayObject 等。如果传入的数据类型不匹配,Vue 将在浏览器控制台发出警告。
  4. 默认值:可以为 props 提供一个默认值,如果父组件没有传递该属性,子组件将使用默认值。
  5. 必需性:通过设置 requiredtrue,你可以指定一个 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>

页面效果

image.png

2. $emit

子组件将数据传递给父组件

2.1 emit 的基本用法:

  1. 注册事件:在子组件中,你可以使用 defineEmits 函数来声明一个或多个自定义事件。
  2. 触发事件:在子组件的逻辑中,你可以调用 emit 函数并传递事件名称和一个或多个参数。这些参数将被作为事件的数据传递给父组件。
  3. 监听事件:父组件可以在模板中通过 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>

效果:

image.png

image.png

3. provide 提供 和 inject 注入

3.1 依赖注入基本介绍

一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。 ---> 引自官方

provide() 函数接收两个参数。第一个参数被称为注入名,可以是一个字符串或是一个 Symbol。后代组件会用注入名来查找期望注入的值。一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值。

image.png

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 的注入名保持一致, 这样才可以正常接收到数据

效果图:

image.png

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>

子组件的实例

image.png

效果:

image.png

调用子组件暴露的方法,父组件点击按钮之后, 执行子组件的那个更新数据的方法

image.png

5. pinia

5.1 介绍

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。

5.2 使用

安装pinia

shell

pnpm add pinia

第二步: 初始化pinia store

创建 Pinia Store

创建一个 userStore.js 文件,用来存放关于用户信息。一般都是在在 src/stores/ 目录中.

image.png

初始化储存库代码

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>

效果

image.png

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 效果

image.png

image.png

7. 结语

通过这次的demo练习, 对于不同的情况组件通信的方式有了更全面的认识.我们在日常开发当中, 需根据具体情况,选择对应的通信方案.


目录
相关文章
|
24天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
24天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
29 8
|
23天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
23 1
|
23天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
33 1
|
27天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
29天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
3天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
1月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
36 1
vue学习第一章
|
1月前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
26 1
vue学习第三章
|
1月前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章
下一篇
DataWorks