深入了解 Vue 3 组件间通信机制

什么是组件?

在 Vue3 中,组件是构建应用界面的核心概念之一。组件可以看作是可复用、自包含和可组合的代码块,用于封装 UI 元素和相应的行为逻辑。

通俗来说就是,组件(Component)是一种对数据和方法的简单封装,每一个组件有自己单独的逻辑,并且可以分别管理。不同的组件组合在一起,就形成了页面。所以,每一个Web页面可以抽象成是不同组件组合而成的,页面只是这些组件的一个容器。并且这些组件可以在不影响程序运行的情况下,随时被替换,利用这种组件化的思想可以将一个巨大的东西拆分成很多小模块,也是现代前端框架的核心思想之一。

在 Vue 中,通常一个应用会以一颗嵌套的组件树的形式来组织,如图所示:

深入了解 Vue 3 组件间通信机制_第1张图片

上图中将整体页面为一个根组件,然后根组件下有三个子组件,分别是页头组件、内容区组件和侧边栏组件。在内容区组件下,又细分出两个内容组件,而侧边栏组件则有三个侧边栏内容组件。所有组件整齐排列,按照树形结构组合,这就是 Vue 内组件的组织结构。

另外 Vue 3 的组件还具有以下特点:

  1. 模块化:组件以模块化的方式进行定义和使用,每个组件都有独立的作用域,使得代码更加结构化和可维护。组件可根据需要进行拆分,形成层次化的组件树结构。

  2. 复用性:组件是可复用的,可以在应用中多次使用。通过将 UI 元素和相关的逻辑封装为组件,可以避免代码重复,并且可以轻松地在不同的上下文中重用组件。

  3. 可组合性:组件可以通过父子组件之间的嵌套与组合,形成更大规模的应用界面。通过传递属性 prop 和监听事件 emit,组件之间可以进行数据和通信的交互。

  4. 响应式:组件内部的数据可以使用 Vue 3 的响应式系统进行管理,当数据发生变化时,组件会自动更新视图。通过响应式系统,可以实现数据的双向绑定和自动渲染。

  5. 生命周期钩子函数:Vue 3 的组件具有一系列的生命周期钩子函数,用于在组件不同的生命周期阶段执行特定的代码逻辑。生命周期钩子函数可以帮助开发者控制组件的行为和实现特定的功能。

  6. 单文件组件:Vue 3 支持使用单文件组件(.vue 文件)的方式来定义和编写组件。单文件组件将组件的模板、样式和逻辑都封装在一个文件中,提高了代码的可读性和维护性。

组件定义

一个 Vue 组件的结构通常包括三个部分:模板(Template)、脚本(Script)和样式(Style)。这些部分一般会放在一个单文件组件(.vue 文件)中,也可以分离成三个独立的文件。

下面是一个典型的 Vue 组件的结构示例:

<template>
  
template>

<script setup>
  // 脚本部分
script>

<style>
  /* 样式部分 */
  /* CSS 样式规则 */
style>

其中:

  1. 模板(Template):模板部分定义了组件的结构和布局,使用 HTML 和 Vue 的模板语法编写。在模板中可以插入动态数据和表达式,并通过指令(如 v-bindv-if)和事件绑定等方式与组件的数据和行为进行交互。

  2. 脚本(Script):脚本部分是组件的逻辑核心,使用 JavaScript 或 TypeScript 编写。在脚本中,可以定义组件的属性、计算属性、方法、生命周期钩子函数等。通过脚本,可以处理组件的数据逻辑、事件响应等功能。

  3. 样式(Style):样式部分定义了组件的样式规则,使用 CSS 或预处理器(如 Sass、Less)编写。可以为组件元素添加类名、样式选择器等,来对组件进行样式修饰和美化。

这种将模板、脚本和样式封装在一个单文件组件中的方式,可以提高代码的可读性和维护性,并且使得组件的结构更加清晰和独立。通过单文件组件,我们可以更好地组织和管理组件的相关资源,并方便地重用和维护组件。

组件注册

在 Vue 中,如果要使用自定义组件,第一步需要做的就是将其注册到应用中。Vue 组件的注册可以有两种方式:全局注册和局部注册。

  1. 全局注册:全局注册的组件可以在整个应用的任何地方使用,无需额外的导入或注册操作。

    全局注册组件的方法是在 main.ts 文件中使用 app.component 方法。例如,将自定义组件 my-component 进行全局注册:

    import { createApp } from 'vue';
    import App from './App.vue';
    import MyComponent from './components/MyComponent.vue';
    
    const app = createApp(App);
    
    app.component('my-component', MyComponent);
    
    app.mount('#app');
    

    在上述示例中,我们首先使用 createApp 创建应用实例,并将根组件 App 作为参数传入。然后,使用 app.component 方法全局注册名为 my-component 的组件,并将其与 MyComponent 组件关联。最后,通过 app.mount 将应用挂载到页面中的 DOM 元素上。

    在全局注册后,我们可以在任何组件的模板中使用 标签来引入和使用该组件,无需在局部组件中重新注册。

  2. 局部注册:局部注册的组件只能在其所属的组件内部使用,无法在其他组件(包括子组件)中直接使用。

    在组合式 API 中组件局部注册时直接引入,然后直接调用即可。例如:

    <script setup>
    import MyComponent from './MyComponent.vue';
      
    script>
    
    <template>
        
        <my-component>my-component>
    template>
    

    在上述代码中,

    在父组件中,我们使用 @btn-click 监听子组件触发的 btn-click 自定义事件,并将 handle 方法指定为事件处理函数。

    当子组件中的按钮被点击时,会触发 btn-click 事件并将消息作为参数传递给父组件的 handle 方法。在 handle 方法中,我们将接收到的消息更新到 message 变量上,从而实现父组件接收子组件发送的消息并进行处理的效果。

    使用订阅发布通信

    Props 属性负责父组件向子组件传递数据,子组件可以通过自定义事件向父组件传递数据。但是如果两个组件不是父子组件关系,而是深度嵌套的组件,并且深层子组件只需要父组件的部分内容,这个时侯如果使用 Props 属性逐级传下去,将会显得非常麻烦而且容易出错。针对这种情况,Vue 推出了发布订阅进行通信,即 Provider/Inject 通信。

    Provider/Inject 通信,需要有一个 Provider 和一个或者多个 Inject。在父组件中,Provider 负责提供数据,深层子组件里的 Inject 负责读取数据。这种通信方式,不管父子组件中间相隔多久,都是可以实现的。

    例如这里的组件层级关系如下:

    ProjectInjectComponent
     ﹂ProjectInjectChild
      ﹂ProjectInjectGrandson
    

    在 ProjectlnjectComponent 中使用 Provide 先发布一条数据, 然后在孙组件 ProjectInjectGrandson 中通过 Inject 订阅这条数据并显示。代码如下:

    //ProjectInjectComponent.vue(父组件)
    <script lang="ts" setup>
    import { provide, ref } from 'vue';
    import ProjectInjectChild from './ProjectInjectChild.vue';
    
    const message = ref<string>("ProjectInjectComponent 组件消息")
    
    //发布数据,key:message
    provide('message',message);
    script>
    
    <template>
        <ProjectInjectChild>ProjectInjectChild>
    template>
    
    //ProjectInjectChild.vue(子组件)
    <script lang="ts" setup>
    import ProjectInjectGrandson from './ProjectInjectGrandson.vue';
    
    script>
    
    <template>
        <ProjectInjectGrandson>ProjectInjectGrandson>
    template>
    
    //ProjectInjectGrandson.vue(孙组件)
    <script lang="ts" setup>
    import { inject, ref } from 'vue';
    
    //订阅数据 key:message,defaultValue:"消息"
    const message = inject<string>('message',"消息")
    script>
    
    <template>
        <h2>{{ message }}h2>
    template>
    

    在 ProjectInjectComponent 组件中通过 Provide 发布了一个名为 message 数据;在嵌套最底层的 ProvideInjectGrandson 组件中通过 Inject 读取父组件发布的 message 数据,并渲染在页面上。因为父组件中的 message 是响应式数据,所以父组件中的数据会同步更新到嵌套的子组件中,最终将更新后的数据重新渲染到页面。

你可能感兴趣的:(Vue3,vue.js,前端,javascript)