Vue 组件的使用不管是在平常工作还是在面试面试中,都是频繁出现的。因此系统的梳理一下组件之间的传参还是非常有必要的
// 第一种数组方式 props: [xxx, xxx, xxx] // 第二种对象方式 props: { xxx: Number, xxx: String} // 第三种对象嵌套对象方式 props: { xxx: { //类型不匹配会警告 type: Number, default: 0, required: true, // 返回值不是 true,会警告 validator(val) { return val === 10} } } 复制代码
第三种对象默认支持 4 种属性,并且都是非必填的。可以随意使用
第一种静态属性传参
注意:
<!--props 接受到的均为 String --> <children xxx="123"></children> <!-- 有只有属性没有值, 这种情况 props 指定类型是 Boolean 则接收到的是 true --> <children xxx></children> 复制代码
第二种动态属性传参
注意:
<!-- 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
$attrs 会获取到 props 中未定义的属性(class 和 style 属性除外),支持响应式。常用的场景有俩种:
$listeners 定义的事件都在子组件的根元素上,有时候想加到其他元素上。就可以使用 $listerners。它包含了父组件中的事件监听器(除了带有 .native 修饰符的监听器)
Vue 默认有 $on $emit $once $off 几种方法来实现发布订阅模式,这也应用在了组件传参上。在组件上添加的特殊方法 @abc="methods" 就相当于使用了 $on 来监听这个方法。因此组件内可以使用 $emit 来进行通知。
这里有一道考题: for 循环的时候如何拿到子组件的传值和 for 中循环的值
答案有俩种,一是 $event, 二是 闭包。只是需要注意 $event 只能获取到第一个值
<template v-for="item in [1, 2, 3]"> <children @abc="((val, val2) => getValue(val, item))"></children> </template> 复制代码
这个其实是一种通过 on 的组合方式。优点再于同步值方便,写法优雅。下面三种写法其实是一个意思
// 写法 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> <!--使用--> <children> <!--跑到默认插槽中去--> <div>123</div> <!--另一种默认插槽的写法--> <template v-slot:default></template> <!--跑到具名插槽 footer 中去--> <template v-slot:footer></template> <!--缩写形式--> <template #footer></template> <!--获取子组件的值--> <template v-slot:header="slot">{{slot.user}}</template> <!--结构插槽值--> <template v-slot:header="{user: person}">{{person}}</template> <!--老式写法,可以写到具体的标签上面--> <template slot="footer" slot-scope="scope"></template> </children> 复制代码
注意:注入的值是非响应的
<!--父组件 提供--> { project() { return { parent: this } } } <!--子组件 注入--> { // 写法一 inject: ['parent'] // 写法二 inject: { parent: 'parent' } // 写法三 inject: { parent: { from: 'parent', default: 222 } } } 复制代码
这个相当于单独维护的一组数据,就不过多的说了。