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
}
}