vue组件传参的八种方式

3,432 阅读2分钟

vue组件传参的方式是无论在工作中,还是面试的时候都会碰到的问题,参考网上的文章,总结一下 原文链接 www.cnblogs.com/bamboopande…

① props传参

子组件定义 props 有三种方式:

//第一种 数组形式
props:['***','***','***']
//第二种 对象形式
props:{ ***:String, ***:Number }
//第三种 嵌套对象方式
props:{
    ***:{
        type: String,
        default: 0,
        required: true,
        // 返回值不是 true,会警告
        validator(val) { return val === 10 }
    }
}

父组件传参:

静态属性传参
1.  在不定义 props 类型的情况下 props 接受到的均为 String。
<children xxx="123"></children>
2.  当 props 属性指定为 Boolean 时,并且只有属性 key 没有值 value 时接受到的是 true
-- 有只有属性没有值, 这种情况 props 指定类型是 Boolean 则接收到的是 true
<children xxx></children>

动态属性传参
1.  需要区分非简写形式传入的值是对象,则会对应 props 中多个值
2.  会保留传入值的类型
3.  如果是表达式则获取到的是表达式的计算结果
//prop 接收到 Number 类型的 123
<children :xxx="123"></children>
//prop 接收到 Array 类型的 [1, 2, 3]
<children v-bind:xxx="[1, 2, 3]"></children>
//prop 会接收到 xxx1 和 xxx2 俩个参数。这种不支持简写形式
<children v-bind="{xxx1: 1, xxx2: 2}"></children>

② attrs 和 listeners

$attrs 会获取到 props 中未定义的属性(class 和 style 属性除外),支持响应式
常用的场景有俩种
1.组件嵌套组件时可以使用 $attrs 来支持过多的属性支持。比如 elementUI 的 table 组件。支持的属性十几个,而平常封装的时候用的最多的也就一俩个。
2.属性默认是添加在父组件上的,有时候想把多余的属性添加在子组件上(可以结合 inheritAttrs: false 属性,让父属性不接受多余的属性)

$listener 包含了父作用域中的 (不含 `.native` 修饰器的) `v-on` 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
简单点讲它是一个对象,里面包含了作用在这个组件上所有的监听器(监听事件),可以通过 v-on="$listeners" 将事件监听指向这个组件内的子元素(包括内部的子组件)。

下面是例子
    <div id="app">
      <child1
        :p-child1="child1"
        :p-child2="child2"
        :p-child-attrs="1231"
        v-on:test1="onTest1"
        v-on:test2="onTest2">
      </child1>
    </div>
      Vue.component("Child1", {
        inheritAttrs: true,
        props: ["pChild1"],
        template: `
        <div class="child-1">
        <p>in child1:</p>
        <p>props: {{pChild1}}</p>
        <p>$attrs: {{this.$attrs}}</p>
        <hr>
        <child2 v-bind="$attrs" v-on="$listeners"></child2></div>`,
        mounted: function() {
          this.$emit("test1");
        }
      });
      Vue.component("Child2", {
        inheritAttrs: true,
        props: ["pChild2"],
        template: `
        <div class="child-2">
        <p>in child->child2:</p>
        <p>props: {{pChild2}}</p>
        <p>$attrs: {{this.$attrs}}</p>
          <button @click="$emit('test2','按钮点击')">触发事件</button>
        <hr> </div>`,
        mounted: function() {
          this.$emit("test2");
        }
      });
      const app = new Vue({
        el: "#app",
        data: {
          child1: "pChild1的值",
          child2: "pChild2的值"
        },
        methods: {
          onTest1() {
            console.log("test1 running...");
          },
         onTest2(value) {
            console.log("test2 running..." + value);
          }
        }
      });
 上例中,父组件在`child1`组件中设置两个监听事件`test1``test2`,分别在`child1`组件和`child1`组件内部的`child2`组件中执行。还设置了三个属性`p-child1``p-child2``p-child-attrs`。其中`p-child1``p-child2`被对应的组件的`prop`识别。所以:\
`p-child1`组件中`$attrs``{ "p-child2": "pChild2的值", "p-child-attrs": 1231 }`;\
`p-child2`组件中`$attrs``{ "p-child-attrs": 1231 }`。
再点击`child2`组件中的按钮,触发事件  控制台打印出 test2 running...按钮点击      

③ $emit 通知

vue 默认有 $on $emit $once $off 几种方法来实现发布订阅模式,这也应用在了组件传参上。在组件上添加的特殊方法 @abc="methods" 就相当于使用了 $on 来监听这个方法。因此组件内可以使用 $emit 来进行通知。

④ v-model

// 写法 1
<children v-model="a"></children>
{ model: { prop: 'value', event: 'update:a', }, methods: { a() { this.$emit('update:a', 1)} } }

// 写法 2
<children :a="a" @update:a="a = $event"></children>
{ props: ['a'] methods: { a() { this.$emit('update:a', 1)} } }

// 写法 3
// 1. 事件名必须是 update: + 属性名
// 2. 参数不能是表达式,最好是 data 里面的属性
<children :a.sync="a"></children>
{ props: ['a'] methods: { a() { this.$emit('update:a', 1)} } }

⑤ 插槽

<template>
    <div>
        <!--默认插槽-->
        <slot></slot>
        <!--另一种默认插槽的写法-->
        <slot name="default"></slot>
        <!--具名插槽-->
        <slot name="footer"></slot>
        <!--传参插槽-->
        <slot v-bind:user="user" name="header"></slot>
    </div>
</template>

⑥ refs root parent children

组件获取组件实例,元素获取元素 
根组件 
父组件 
子组件(所有的子组件,不保证顺序)

⑦ project/inject 注入的值是非响应的

// 父组件 提供
project(){
    return{
        parent:this
    }
}

//子组件 注入
inject: ['parent']
inject: { parent: 'parent' }
inject: {
    parent: {
        from:"parent",
        default:2
    }
}

⑧ Vuex