场景介绍
vue中的属性绑定只能是父组件传递给子组件。当你有这样的需求:你想向嵌套层级比较深的组件传递数据的时候,只能由父组件传递给子组件,子组件再传递给孙子组件,例如:
<parent-component :passdown="passdown">
<child-component :passdown="passdown">
<grand-child-component :passdown="passdown">
....
就这样一层一层的往下传递passdown这个变量,最后才能用{{passdown}}。
当我们传递几个或10几个嵌套级组件的情况来看,我们就要在每个组件中不停地props,每个必须写很多遍,让代码看起来很累赘,那有没有什么更简便的方法呢?答案是肯定的,
- 通过vuex通信,
- 通过inheritAttrs,以及实例属性$attrs
<template>
<div class="home">
<mytest :title="title" :massgae="massgae"></mytest>
</div>
</template>
<script>
export default {
name: 'home',
data () {
return {
title:'title1111',
massgae:'message111'
}
},
components:{
'mytest':{
template:`<div>这是个h1标题{{title}}</div>`,
props:['title'],
data(){
return{
mag:'111'
}
},
created:function(){
console.log(this.$attrs)//注意这里
}
}
}
}
</script>
上边的代码当中,我们只在子组件中用了title这个属性,message属性是没用到的,那么下面浏览器渲染出来是什么样呢?
如下图:
我们看到: 组件内未被注册(未在props中注册,在本组件中不需要用到的属性)的属性将作为普通html元素属性被渲染,但是我们又向要向下传递,又不想要未被注册的属性作为普通html元素属性被渲染,那还有什么方法呢?在Vue2.4.0中,可以在组件定义中添加inheritAttrs:false,组件将不会把未被注册的属性呈现为普通的HTML属性。但是在组件中我们可以通过其$attrs可以获取到没有注册的属性。
components:{
'mytest':{
template:`<div>这是个h1标题{{title}}</div>`,
props:['title'],
inheritAttrs: false,
data(){
return{
mag:'111'
}
},
created:function(){
console.log(this.$attrs)//注意这里
}
}
```
渲染效果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019112618072475.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqbTEzMjQ5NDI1Mjgw,size_16,color_FFFFFF,t_70)
## 补充:说一下$attrs的使用
有一个页面有父组件,子组件,孙子组件构成,如下:
<template>
<div style="padding:50px;">
<childcom :name="name" :age="age" :sex="sex"></childcom>
</div>
</template>
<script>
export default {
'name':'test',
props:[],
data(){
return {
'name':'张三',
'age':'30',
'sex':'男'
}
},
components:{
'childcom':{
template:`<div>
<div>{{name}}</div>
<grandcom v-bind="$attrs"></grandcom>
</div>`,
props:['name'],
components: {
'grandcom':{
template:`<div>{{$attrs}}</div>`,
}
}
}
}
}
</script>
效果图:
说明:如果attrs被绑定在子组件childcom上,我们就可以在孙子组件grandcom中获取到this.KaTeX parse error: Expected '}', got 'EOF' at end of input: attrs的值。这个{{attrs}}的值只是父组件中传递下来的props(除了在子组件childcom组件中props声明的)
特别注意:记住孙子组件grandcom里获取到this. a t t r s 的 值 是 除 了 子 组 件 c h i l d c o m 声 明 的 元 素 ! 记 住 是 除 了 子 组 件 c h i l d c o m 声 明 的 元 素 ! 例 如 上 面 的 代 码 我 在 子 组 件 c h i l d c o m 组 件 的 p r o p s 里 声 明 了 n a m e , 那 么 我 在 孙 子 组 件 g r a n d c o m 里 获 取 到 的 attrs的值是除了子组件childcom声明的元素!记住是除了子组件childcom声明的元素!例如上面的代码我在子组件childcom组件的props里声明了name,那么我在孙子组件grandcom里获取到的 attrs的值是除了子组件childcom声明的元素!记住是除了子组件childcom声明的元素!例如上面的代码我在子组件childcom组件的props里声明了name,那么我在孙子组件grandcom里获取到的attrs就不包含name属性,那么this.$attrs = { ‘age’:‘30’, ‘sex’:‘男’}。
补充以下:inheritAttrs属性
- 关于inheritAttrs这个属性跟获取到$attrs的值没有关系,inheritAttrs通常在编写基础组件时候会用到。
- 注意:这个选项不影响 class 和 style 绑定。
- 在Vue2.4.0之前版本,组件内未被注册的属性将作为普通html元素属性被渲染。
inheritAttrs到底有啥用?到底用在哪里?
<template>
<childcom :name="name" :age="age" type="text"></childcom>
</template>
<script>
export default {
'name':'test',
props:[],
data(){
return {
'name':'张三',
'age':'30',
'sex':'男'
}
},
components:{
'childcom':{
props:['name','age'],
template:`<input type="number" style="border:1px solid blue">`,
}
}
}
</script>
上面代码你觉得input上会怎么显示? 父组件传递了type=“text”,子组件里input 上type=“number”,那渲染到页面会是什么样?渲染图如下:
看到没,父组件传递的type="text"覆盖了input 上type=“number”,这岂不是把我的input数据类型都给改变了,这岂不是有问题,这不是我想要的!!!!看到这里明白了吗?回头去体会下上面官网的原话!!!
需求:我需要input 上type="number"类型不变,但是我还是要取到父组件的type="text"的值,那么代码如下:
<template>
<childcom :name="name" :age="age" type="text"></childcom>
</template>
<script>
export default {
'name':'test',
props:[],
data(){
return {
'name':'张三',
'age':'30',
'sex':'男'
}
},
components:{
'childcom':{
inheritAttrs:false,
props:['name','age'],
template:`<input type="number" style="border:1px solid blue">`,
created () {
console.log(this.$attrs.type)
}
}
}
}
</script>
页面渲染图:
到这,我想大家都明白了inheritAttrs的作用了吧。默认情况下vue会把父作用域的不被认作 props 的特性绑定 且作为普通的 HTML 特性应用在子组件的根元素上。绑定就绑定,显示就显示,没啥大不了的,但是怕就怕遇到一些特殊的,就比如上面的input的情况,这个时候inheritAttrs:false的作用就出来啦。
补充一下:$listeners
父组件-子组件-孙子组件,,,,现在我要你在孙子组件里改变父组件的值,怎么改?有很多方法啦,但是$listeners给我们提供了一个新的思路。话不多说,直接上代码
<template>
<div>
<childcom :name="name" :age="age" :sex="sex" @testChangeName="changeName"></childcom>
</div>
</template>
<script>
export default {
'name':'test',
props:[],
data(){
return {
'name':'张三',
'age':'30',
'sex':'男'
}
},
components:{
'childcom':{
props:['name'],
template:`<div>
<div>我是子组件 {{name}}</div>
<grandcom v-bind="$attrs" v-on="$listeners"></grandcom>
</div>`,
components: {
'grandcom':{
template:`<div>我是孙子组件-------<button @click="grandChangeName">改变名字</button></div>`,
methods:{
grandChangeName(){
this.$emit('testChangeName','kkkkkk')
}
}
}
}
}
},
methods:{
changeName(val){
this.name = val
}
}
}
</script>
页面渲染如下:
$listeners可以让你在孙子组件改变父组件的值,是不是很方便…