2019/1/5
在vue中通过使用$attrs实现组件之间的数据传递
组件之间传递数据的方式有很多种,之所以有这么多种方式,是为了满足在不同场景不同条件下的使用
三种常用组件传递值的方式
- 通过props的方式向子组件传递(父子传递)
- vuex 进行状态管理
- 非父子组件的通信传递Vue Event Bus,使用Vue的实例,实现事件的监听和发布,实现组件之间的传递
$attrs的概念
包含了父作用域中不作为prop被识别(且获取)的特性绑定(class和style除外)。 当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外)。 并且可以通过v-bind=“$attrs” 传入内部组件-在创建高级别的组件时非常有用
通俗点讲:$attrs可以手机父组件中的所有传过来的属性除了那些在组建中没有通过props定义的。
引申说明一下,如果组件嵌套层级有点深但是又不那么深,比如三层。 如果我们使用props的话,最里面的组件想要获取最外层组件的数据,就是通过中间的组件的props来传递,但是这个props对于中间的这个组件没啥用处,就是做了一个桥梁而已。平常写代码的时候经常遇到。例如下面情景
// 主组件
<template>
<div>
<father :name='name'
:sex="sex"
:age="age"></father>
</div>
</template>
<script>
import father from "./father.vue"
export default {
name: 'test',
components: {
father
},
data () {
return {
name: '测试',
sex: '男',
age: 18,
}
}
}
</script>
//father 组件
<template>
<div>
<ul>
<li>姓名:{{name}}</li>
<!-- <child v-bind="$attrs"></child> -->
<child :sex="sex"></child>
<li>年龄:{{age}}</li>
</ul>
</div>
</template>
<script>
import child from "./child.vue"
export default {
name: 'father',
components: {
child
},
data () {
return {
newAge: this.age
}
},
props: {
name: {
type: String,
default: '',
},
sex: {
type: String,
default: ''
},
age: {
type: [Number, String],
default: 0,
}
},
}
</script>
//child组件
<template>
<div>
<h2>性别:{{sex}}</h2>
</div>
</template>
<script>
export default {
name: 'child',
props: {
sex: {
type: String,
default: '',
}
},
data () {
return {
newSex: this.sex,
}
},
}
</script>
虽然这种方式也能实现我们想要的效果,如果传的值少的话,其实也没啥影响,但是如果传的值很多,就会影响代码,这个时候就可以使用$attrs这种api,大大解决了我们的问题。
$attrs具体的使用方式
//主组件
<template>
<div>
<father :name='name'
:sex="sex"
:age="age"></father>
</div>
</template>
<script>
import father from "./father.vue"
export default {
name: 'test',
components: {
father
},
data () {
return {
name: '测试',
sex: '男',
age: 18,
}
}
}
</script>
//father组件
<template>
<div>
<ul>
<li>姓名:{{name}}</li>
<child v-bind="$attrs"></child>
<!-- <child :sex="sex"></child> -->
<li>年龄:{{age}}</li>
</ul>
</div>
</template>
<script>
import child from "./child.vue"
export default {
name: 'father',
components: {
child
},
data () {
return {
newAge: this.age
}
},
props: {
name: {
type: String,
default: '',
},
age: {
type: [Number, String],
default: 0,
}
},
}
</script>
//child组件
<template>
<div>
<h2>性别:{{sex}}</h2>
</div>
</template>
<script>
export default {
name: 'child',
props: {
sex: {
type: String,
default: '',
}
},
data () {
return {
newSex: this.sex,
}
},
methods: {
},
}
</script>
注意当子组件使用emit("update:xx",xx),是没有作用的
当孙子组件传递给信息给爷爷组件时就需要使用$listeners
$listeners 概念
包含了父作用域中的(不含.native修饰器)v-on事件监听器。它可以通过v-on="$listeners" 传入内部组件--在创建更高层次的组件时非常有用 (孙传父专用),解觉子传父这个功能。
示例代码
//主组件
<template>
<div>
<father :name='name'
:sex="sex"
:age="age"
@getChildSex="getChildSex"></father>
</div>
</template>
<script>
import father from "./father.vue"
export default {
name: 'test',
components: {
father
},
data () {
return {
name: '测试',
sex: '男',
age: 18,
}
},
methods: {
getChildSex (val) {
this.sex = val;
console.log(val);
}
}
}
</script>
//father组件
<template>
<div>
<ul>
<li>姓名:{{name}}</li>
<child v-bind="$attrs"
v-on="$listeners"></child>
<!-- <child :sex="sex"></child> -->
<li>年龄:{{age}}</li>
</ul>
</div>
</template>
<script>
import child from "./child.vue"
export default {
name: 'father',
components: {
child
},
data () {
return {
newAge: this.age
}
},
props: {
name: {
type: String,
default: '',
},
age: {
type: [Number, String],
default: 0,
}
},
}
</script>
//child组件
<template>
<div>
<h2>性别:{{sex}}</h2>
<button @click="changeSex">切换性别</button>
</div>
</template>
<script>
export default {
name: 'child',
props: {
sex: {
type: [String, Number],
default: '',
}
},
data () {
return {
newSex: this.sex,
}
},
methods: {
changeSex () {
this.newSex = this.sex;
this.$emit('getChildSex', this.sex == '男' ? '女' : '男');
}
},
}
</script>
其实也可以这么理解v-bind="listeners" 两者结合使用的,一个是传值给孙组件,一个是孙组件通知主组件进行数据传递。形成一个完整的流程。
可以用一张图分析观看