Vue3中组件数据通信方式总结

 更新时间:2023年06月02日 15:53:19   作者:书源  
如果在面试中,面试官问你Vue组件之间有哪些数据通信方式,你会怎么回复,不要担心,本文为大家整理了超全的Vue3中组件数据通信方式,需要的小伙伴快收藏起来吧

如果在面试中,面试官问你Vue组件之间有哪些数据通信方式,你会怎么回复?

要回答这个问题,我们先来了解一下组件之间数据通信有哪些场景。

如图所示,组件之间数据通信有父子组件之间通信,跨级组件之间通信以及兄弟组件之间通信三种场景,那这三种场景分别有哪些通信手段呢?

父子组件通信

相信大家对这个场景都很熟悉,我这里简单总结下这个场景下的通信方案。

props

在 Vue.js 中实现“父子组件”单向数据通信,一般都是通过 Props 来进行的。

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,这避免了子组件意外修改父组件状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

每次父组件更新后,所有的子组件中 props 都会被更新到最新值,这意味着我们不应该在子组件中去更改一个 prop。如果做了,Vue 会在控制台上向你抛出警告:

const props = defineProps(['foo'])
// ❌ 警告!prop 是只读的!
props.foo = 'bar'

如果我们在需求中需要更改 prop怎么办?答案是子组件可以抛出一个事件$emit来通知父组件做出改变。

$emit

在子组件中可以直接使用 $emit 方法触发自定义事件,父组件可以通过 v-on (缩写为 @) 来监听事件,然后在监听的回调函数中做出数据的改变。示例:

<!-- 子组件触发事件 -->
<button @click="$emit('someEvent')">click me</button>
<!-- 父组件监听 -->
<MyComponent @some-event="callback" />

通过$emit,子组件可以通过事件参数向父组件传递数据。

不过这种获取子组件数据的方式比较被动,需要等待子组件事件的触发,但一些特殊场合下父组件需要主动获取子组件数据,这时又该如何处理呢?

ref

ref指的是模版引用,它可以直接访问DOM元素,也可以被用在一个子组件上,获取组件实例,进而操作对应元素或者获取数据。

示例,对 DOM 的直接操作:

<script setup>
import { ref, onMounted } from 'vue'
// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null)
onMounted(() => {
  // 用来从父级组件聚焦输入框
  input.value.focus()
})
</script>
<template>
  <input ref="input" />
</template>

示例,对子组件的直接操作:

<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'
const child = ref(null)
onMounted(() => {
  // child.value 是 <Child /> 组件的实例
})
</script>
<template>
  <Child ref="child" />
</template>

其它的父子组件通信方式诸如$parent等等,大家请自行理解啦,接下来我们来看下跨级关系的组件如何通信。

跨级组件通信

这个场景下,适合用 provide/inject 进行处理,它允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深。祖先组件中通过 provider 来提供变量,子孙组件中通过 inject 来注入变量,不过它的使用场景,主要是子组件获取上级组件的状态。

我们来看个简单的使用案例:

<script setup> 
import { ref, provide } from 'vue'
// 提供静态值
provide('foo', 'bar') 
// 提供响应式的值
const count = ref(0)
provide('count', count)
</script>
<script setup>
import { inject } from 'vue'
// 注入值的默认方式
const foo = inject('foo')
// 注入响应式的值
const count = inject('count')
</script>

需要说明的是 provide/inject 在父子组件通信中虽然也OK,但更多的场景是子孙组件。

兄弟组件通信

看到这个场景,有没有朋友想到我们可以借助与父组件通信,来完成兄弟组件通信?纵然不看代码,也能想到这种方案十分繁杂。

借用响应式数据文件

于是乎,我们可以考虑换个方案,把通信数据都放在一个响应式数据的文件里,所有通信需要的组件都直接引用这个文件里的数据,然后直接在各自组件间进行读数据或写数据。如果有组件里的模板视图使用到这个公共响应式数据,数据被其它组件修改,那也会同时触发模板视图的更新。这么多文字看着很抽象,我们来看下示例:

store.js,存放响应式数据的文件:

import { reactive } from "vue";
export const store = reactive({
  text: "这里是公共响应式数据文件",
});

B.vue:

<template>
  <div>
    <div>B 组件</div>
    <div>store:{{ store.text }}</div>
  </div>
</template>
<script setup>
import { store } from "./store";
</script>

C.vue:

<template>
  <div>
    <div>C 组件</div>
    <div>store:{{ store.text }}</div>
  </div>
</template>
<script setup>
import { store } from "./store";
</script>

父组件:

<template>
  <div @click="handle">change</div>
  <B></B>
  <C></C>
</template>
<script setup>
import B from "./components/B.vue";
import C from "./components/C.vue";
import { store } from "./components/store";
function handle() {
  store.text = "改变数据文件";
}
</script>

B组件和C组件通过响应式数据文件里的store进行通信,当我们在父组件里改了store.text数据,子组件的视图也会自动更新。

不过聪明的你肯定也发现了,虽然这样兄弟组件可以互相通信,但是呢,一旦公共响应式数据变得庞大,所有引用组件都可以自由修改数据,那么数据流向管理将会变得很混乱,不好管理和维护。

既然我们遇到了这样的问题,别人同样会遇到,于是乎Vue官方为我们提供了Pinia,一个数据管理的 JavaScript 库。

Pinia

这里我想借鉴一下Pinia官网对Pinia的描述,更详细的描述可以参考官网。

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。如果你熟悉组合式 API 的话,你可能会认为可以通过一行简单的 export const state = reactive({}) 来共享一个全局状态。对于单页应用来说确实可以,但如果应用在服务器端渲染,这可能会使你的应用暴露出一些安全漏洞。 而如果使用 Pinia,即使在小型单页应用中,你也可以获得如下功能:

Devtools 支持

  • 追踪 actions、mutations 的时间线
  • 在组件中展示它们所用到的 Store
  • 让调试更容易的 Time travel

热更新

  • 不必重载页面即可修改 Store
  • 开发时可保持当前的 State

插件:可通过插件扩展 Pinia 功能

为 JS 开发者提供适当的 TypeScript 支持以及自动补全功能。

支持服务端渲染

总结

今天我们一起了解了Vue组件通信的3个场景:

父子组件:父组件可以通过props向子组件传递数据,子组件可以通过**$emit** 方法触发父组件接收数据,父组件还可以通过模版引用主动获取子组件数据。

跨级组件:一般通过provider/inject传递数据,其实也可以Pina进行通信

兄弟组件:简单的场景我们可以借助于响应式数据文件来完成通信,复杂的场景可以使用Vue官网提供的Pinia库来管理数据。

到此这篇关于Vue3中组件数据通信方式总结的文章就介绍到这了,更多相关Vue3组件数据通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vant中list的使用以及首次加载触发两次解决问题

    vant中list的使用以及首次加载触发两次解决问题

    这篇文章主要介绍了vant中list的使用以及首次加载触发两次解决问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 基于vue实现多引擎搜索及关键字提示

    基于vue实现多引擎搜索及关键字提示

    这篇文章主要为大家详细介绍了基于vue实现多引擎搜索及关键字提示的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • webstorm添加vue.js支持的方法教程

    webstorm添加vue.js支持的方法教程

    因为本人使用的是webstorm2016 2.3版本,结果竟然不支持vue文件,所以找到了一个解决方法,下面这篇文章主要给大家介绍了关于webstorm添加vue支持的方法教程,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-07-07
  • electron踩坑之dialog中的callback解决

    electron踩坑之dialog中的callback解决

    这篇文章主要介绍了electron踩坑之dialog中的callback解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • vue2.0实现前端星星评分功能组件实例代码

    vue2.0实现前端星星评分功能组件实例代码

    本文通过实例代码给大家介绍了vue2.0实现前端星星评分功能组件,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2018-02-02
  • vue中引用swiper轮播插件的教程详解

    vue中引用swiper轮播插件的教程详解

    这篇文章主要介绍了vue中引用swiper轮播插件的方法,在需要使用swiper的组件里引入swiper,swiper的初始化放在mounted里。具体实例代码大家跟随脚本之家小编一起看看吧
    2018-08-08
  • Vue3封装全局Dialog组件的实现方法

    Vue3封装全局Dialog组件的实现方法

    3封装全局Dialog组件相信大家都不陌生,下面这篇文章主要给大家介绍了关于Vue3封装全局Dialog组件的实现方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • Vue.js如何获取data-*的值

    Vue.js如何获取data-*的值

    这篇文章主要介绍了Vue.js如何获取data-*的值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • 详解vue3中如何使用shaka-player

    详解vue3中如何使用shaka-player

    这篇文章主要为大家介绍了vue3中如何使用shaka-player示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 前端vue中实现文件下载的几种方法总结

    前端vue中实现文件下载的几种方法总结

    这篇文章主要介绍了前端vue中实现文件下载的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论