• Vue3.x 从零开始(四)—— 更完善的组件传参


    在如今的前端开发工作中, 组件之间的参数传递是一个非常常见的问题

    Vue 2 已经有了一套非常实用的组件传参机制,Vue 3 在原本的基础上做了些改进

     

     

    一、父组件传参到子组件

    《Vue3.x 从零开始(二)—— 重新认识 Vue 组件》中已经介绍过 Props

    这是最常用的父对子传参方式 

     

    上面演示的参数只是简单的字符串,也可以通过 v-bind 指令传入 Number、Function、Object 等类型

     

    除了传递基本的参数之外,props 还可以用来传递组件

    由于组件是变量的形式传入,所以在子组件中需要动态渲染组件,这就会用到内置组件 <component />

    <component /> 组件会接收 is 参数,并基于这个参数渲染组件,所以我们只要通过 is 属性传入组件变量即可

    子组件定义 prop:

    父组件传入组件: 

    在父组件部分,我们需要把 Alert 组件传给子组件,所以需要引入组件之后,将 Alert 组件保存到 data

    data 是具有响应性的,而组件作为变量传递的时候,是不需要具备响应性的

    所以我使用了 markRaw 方法来消除响应性( markRaw 会标记一个对象,使其永远不会转换为代理,只返回对象本身)

    而在 Vue 2.x 中并没有类似的方法,会对整个组件做数据劫持,导致额外的性能开销

     

    在写文的时候有同事提出了一个问题:prop 传入组件和 slot 有什么区别?

    slot 是在父组件中插入组件,被插入的内容和子组件无关,所有逻辑都在父组件中完成

    而 prop 传入的组件恰恰相反,父组件只是决定传入的内容,相关逻辑是在子组件中完成

     

     

    二、子组件传参到父组件

    子组件通常使用自定义事件的方式向父组件传参,即 $emit

    this.$emit('event-name', data);

    $emit 函数接收的第一个参数是自定义的事件名称,这个事件名称建议采用全小写的 kebab-case 事件名

    除了事件名称外,$emit 还可以接收数量不定的额外参数,这些额外参数会按顺序传递给父组件的事件处理函数


    来看一下自定义事件的完整用法,首先在子组件中通过 $emit 定义事件和需要传递的参数

    然后在父组件中监听该事件,并通过事件处理函数接收子组件的传参

     


    通过 $emit 我们还可以做一些更厉害的事情,比如对 prop 实现双向绑定

    prop 是单向下行绑定,也就是说,父级 prop 的更新会在子组件中响应,而子组件无法修改 prop 的值

    如果子组件确实需要修改 prop 的值,需要使用 update:prop 事件

    比如有一个 prop 的属性名为 text,我们可以在子组件中通过 $emit 触发 update:text 事件并传参,然后在父组件进行赋值

    Vue 3 为了提升开发者的效率,还提供了 v-model 语法。在父组件中使用 v-model:prop ,就不需要监听 update 事件了

    // Vue 2 中的 .sync 修饰符已移除

     

    但子组件还是要用 $emit 触发 update 事件 this.$emit('update:text', data); 

     

    如果是 Vue 2 的用户,应该已经发现 Vue 3 中 v-model 的用法已经发生了改变

    在 Vue 2 中,在组件上使用 v-model 相当于绑定了一个属性名为 value 的 prop,并监听了 input 事件

    而在 Vue 3 中,v-model 相当于传递了一个名为 modelValue 的 prop,并监听 update:modelValue 事件 

    <child-component v-model="text" />
    <!-- 在 Vue 3 中,这两种写法是等价的 -->
    <child-component
      :modelValue="text"
      @update:modelValue="text = $event"
    />

    也就是说,Vue 3 中的 v-model 是 prop + update 的语法糖,只是当 prop 被定义为 modelValue 的时候可以省略 :modelValue 

     

     

    三、深层次的组件传参

    上面介绍是父子组件之间的数据传递,而对于深嵌套的祖孙组件:

    App.vue
    └─ Home.vue
       └─ Footer.vue
          ├─ FooterItem.vue
          └─ FooterTips.vue

    像这样的结构,如果 Home 要传递一个参数给 FooterTips,继续使用 prop 或者 $emit 就会很复杂

    // 在 Vue 2 中可以使用 event bus 来处理,但 Vue 3 中移除了 $on、$off,所以已经无法构建 event bus 了

    这时候可以使用 provide / inject

    首先在孙组件 footer-tips 中通过 inject 定义需要传入的参数,inject 可以是一个由属性名组成的字符串数组

    然后在祖父级组件中通过 provide 传入对应的参数

     

    provide 也可以是一个对象,但为了更安全的开发组件,建议始终将 provide 定义为返回对象的函数

    如果需要定义 inject 的默认值,也可以像 props 一样,将 inject 定义为对象:

    inject: {
      author: {
        default: '这是一个沉默的作者',
      },
      // 如果是 Object 或者 Array 这种引用类型,需要用函数返回
      info: {
        default: () => ({
          name: 'wise',
          home: 'China',
        }),
      },
    },

     

    在上一篇博客《Vue3.x 从零开始(三)—— 使用 Composition API 优化组件》中已经介绍过 setup

    如果需要在 setup 中使用 provide,需要引入 Vue 提供的 provide 全局方法:

    import { provide, ref } from 'vue';
    
    setup() {
      // 使用 ref 提供响应性
      const author = ref('Wise.Wrong');
      // provide 可以定义两个参数,分别为 key 和 value
      provide('author', author.value);
    }

    同样的,setup 中的 inject 也需要全局引入

    import { inject } from 'vue';
    
    setup() {
      // inject 接收两个参数,分别为 key 和默认值,默认值可以为空
      const author = inject('author', '这里是默认值');
      return { author };
    },

     

      

    四、子组件传参到子组件

    在工作中经常也会遇到平级的两个组件组件的通信

    App.vue
    └─ Home.vue
      ├─ Header.vue
      └─ Footer.vue

    比如这里的 Header 和 Footer 都是 Home 的子组件,Footer 中有某个字段受 Header 的影响

    对于这种情况,应该将交互逻辑放到父组件中处理,这种思路叫做状态提升

    比如上图的例子,可以在父组件 Home 中定义一个字段,通过 prop 传入 Footer 组件

    然后在 Header 组件中通过 $emit 触发自定义事件,抛出需要传递给 Footer 的数据

    同时在 Home 组件中监听该事件,并将接到的参数赋值到传入 Footer 的 prop

     

    子组件与子组件的通信,在实际业务场景中会有所不同,但只要牢记状态提升,将交互逻辑放到父组件来处理,绝大部分情况都能迎刃而解


      

    除了上面提到的情况外,还有可能遇到特别复杂的情况,比如:

    1. 孙组件对祖父级组件传参;

    2. 孙组件对孙组件传参。

    通常来说,这些问题都可以通过良好的组件设计来规避

    但随着业务规模的不断扩大,有些复杂的业务场景确实需要直面这些问题,这时候就需要进行状态管理

    Vue 团队开发了 Vuex 来集中式存储和管理应用中所有组件的状态

    在后面的文章中我会提到如何在 Vue 3 中使用 Vuex,但不会单独介绍 Vuex 的用法

    关于 Vuex 的基本用法可以参考我以前的博客《Vue 爬坑之路(四)—— 与 Vuex 的第一次接触》

    如果想更进一步,建议阅读 Vuex 的官方文档~

     

  • 相关阅读:
    我到 vim 配置文件---------修改从---http://www.cnblogs.com/ma6174/archive/2011/12/10/2283393.html
    Bayer图像处理
    Ubuntu 12.04下安装OpenCV 2.4.2
    vim寄存器与复制粘贴的实现
    window 驱动
    js 面试题
    angular 写的一个分页功能
    angular scope 方法
    avalon 框架
    贴几个常用的基础函数
  • 原文地址:https://www.cnblogs.com/wisewrong/p/13813985.html
Copyright © 2020-2023  润新知