Vue3组件通信之props
前⾔:
在开发⼯程中,我们经常会遇到组件之间相互进⾏通信,⽐如在⼀个组件内使⽤多个Button,每个地⽅的Button展⽰内容不同,执⾏⽅法不同,那么我们就需要该组件传递给Button⼀些数据,让Button组件进⾏展⽰。⼜⽐如⼦组件中发⽣⼀些事件,需要由⽗组件来完成某些操作来修改⽗组件⾥的值,那么需要⼦组件向⽗组件传递事件以及⼀些参数。这⼉记录⼀下 Vue3 中组件之间通信之props。
⽗⼦组件之间的通信⽅式:
⽗组件传递给⼦组件: 通过 props 属性;
⼦组件传递给⽗组件: 通过 $emit 触发事件;
⾸先先看看⽗组件是如何向⼦组件传递参数的?
什么是props?
props 是通过在组件上注册⼀些⾃定义的属性(attribute);
通过⽗组件给这些属性(attribute)赋值,或者通过v-bind绑定⽗组件中data中的值,⼦组件再通过属性的名称来获取对应的值;
字符串数组⽤法举例:
// App.vue
<template>
<Child :firstName="firstName" :lastName="lastName" v-bind="info"/>
// 当需要传递的值为对象时,可以直接通过bind绑定,也可以分开通过属性名进⾏绑定。
<Child v-bing="info"></Child>
<Child :age="info.age" :height="height"></Child>
</template>
<script>
import Child from './components/Child.vue'
export default {
name: 'App',
components: {
Child
},
我的英文data() {
return {
firstName: '哈喽',
lastName: '欢迎您!'
info: {
age: "18岁",
height: '188cm'
}
}
}
}
</script>
下⽅是⼦组件:
许多用英语怎么说
// Child.vue
<template>
<div>
<h3>{{ firstName + ',' + lastName}}</h3>
<h3>{{info.age + '的我今年⾝⾼' + info.height}}</h3>
</div>
</template>
<script>
export default {
name: 'Child',
props: ["firstName", "lastName", "age", "height"]
}
</script>
乌龟放多少水合适通过对象绑定时,⽗组件可以直接使⽤ v-bind=“对象名” 进⾏传值,那么⼦组件同样通过对象⾥的属性名进⾏取值。
数组⽤法中我们只能说明传⼊的属性的名称,⽽不能对这些属性值进⾏约束。
对象类型举例:
// Child.vue
<template>
<div>
<h3>{{ firstName + ',' + lastName}}</h3>
<h3>{{age + '的我今年⾝⾼' + height}}</h3>
</div>
</template>
<script>
export default {
name: 'Child',
props: {
firstName: String,
lastName: String,
age: String,
height: {
type: String, // 传⼊的类型
required: true, // required 为true表⽰该属性为必传选项 (required和default分开使⽤)
篮球起源于哪个国家default: "Hello", // 默认值,当该属性没有进⾏传值,该属性默认值为"Hello"
}
}
}
</script>
如果传⼊的值不符合约束类型,那么在浏览器中就会报出警告:该属性希望得到⼀个String类型的值,实际上得到是⼀个Number类型值。
通过对象形式定义props,不仅可以通过type属性来约束值的类型,还可以控制指定传⼊的属性是否是必传的,当属性没有传⼊值时属性的默认值。
下⾯我们再来看看type还有哪些类型?
String
Number
Boolean
Array
Object
Data
Function
Symbol
下⾯简单写⼀下各个类型的写法:(⾃⼰也顺便加深下印象)
props: {
招标管理办法
obj: { // 带有默认值的对象
type: Object,
default() { //这⼉类型为Object必须通过⼀个⼯⼚函数获取,类似于data(){},防⽌堆地址相同
return { grade: 90}
}
},
funC: {
type: Function,
default() {
return "Default function" // 默认返回⼀个函数
}
},
numB: { // 带有默认值的数字
type: Number,
default: 100
},
str: { // 带有默认值的字符串
type: String,
default: 'heihei'
}
}
从上⾯可以看出,props有两种常见的⽤法:
1. 字符串数组,数组中的字符串就是属性(attribute)的名称;(⽆法对传进来的值进⾏约束)
2. 对象类型,对象类型我们可以在指定属性(attribute)名称的同时,指定它需要传递的类型、默认值、以及是否必须等等;$attrs
当我们在⽗组件向⼦组件传递了某个属性,但是在⼦组件中并没有通过props取值时,那么可以通过this.$attrs来获取,⽐较常见的是class、style、id属性等等;
举个例⼦:
// ⽗组件(⽗组件向⼦组件传递了4个属性值)
<Child :firstName="firstName" :lastName="lastName" :age="info.age" :height="info.height"></Child>
<template>
<div>
<h3>{{ firstName + ',' + lastName}}</h3>
</div>
</template>
<script>
export default {
name: 'Child',
props: {
firstName: String,
lastName: String
},
created() {
console.log(this.$attrs) // Proxy {age: "18岁", height: "188cm", __vInternal: 1}
}
}
</script>
所以,我们可以直接在⼦组件上这样写
<template>
<div>
<h3>{{ firstName + ',' + lastName}}</h3>
<h3>{{ $attrs.age + '的我今年⾝⾼' + $attrs.height}}</h3>
</div>
</template>
<script>
export default {
name: 'Child',
props: {
firstName: String,
lastName: String,
}
}
</script>
通过$attrs⼀样能够使⽤⽗组件传递过来的值。注意:($attrs⾥包含的属性是在props 中没有定义的属性)
当我们在⽗组件中传递了⼀个class,我们看看会发⽣什么?
// App.vue
<Child :firstName="firstName" :lastName="lastName" class="content"></Child>
⼦组件中:
<div>
<h3>{{ firstName + ',' + lastName}}</h3>
<h3>{{ $attrs.age + '的我今年⾝⾼' + $attrs.height}}</h3>
</div>
</template>
稀罕
<script>
export default {
name: 'Child',
props: {
firstName: String,
lastName: String,
诗意昵称}
}毕业论文题目
</script>
<style scoped>
.content {
color: red;
}
</style>
当⽗组件再加⼀个属性,⼦组件props依然只定义(firstName, lastName)如下:
// App.vue
<Child :firstName="firstName" :lastName="lastName" :age="info.age" class="content"></Child>
我们会发现,⼦组件中的字体颜⾊变为红⾊,age属性加在了组件的根节点上。(我们知道template是不会加在到dom上的)
那如果不想要这个属性继承到根节点上,怎么办呢?