如果存在组件之间层级大于2层,中间需要一个过渡层的时候,属性和事件的上传下达越简洁越好,重点就是采用vue里的$atts 和事件 $listeners,先打印看看这两者是什么玩意,
1 2
| $attrs: object, $listeners: object
|
两者都是绑定在组件里的,且是对象类型,所以在组件阔以之间用this.$attrs.info
去获取祖父组件传来的info信息。
以下有三个组件,三者之间都是相关有联系的,阔以称之为 祖父组件、父组件以及子组件。
伪代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| // grandParent.vue <template> <div class="home"> <Parent :childMsg='childMsg' @triggerClickChild='triggerClickChild' info='父组件' /> </div> </template>
<script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import Parent from '../components/parent.vue'; // @ is an alias to /src
@Component({ components: { Parent, }, })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| // parent.vue <Child label='子组件信息' class='child' v-bind='$attrs' v-on='$listeners' @triggerClickChild='parentC' />
import Child from './child.vue' @Component({ components: { Child } }) export default class Parent extends Vue { @Prop() private childMsg!: any; // 此时childMsg信息已用所以不会传递到子组件 private parentC(key: string) { console.log(key, '中间层截胡') } private mounted() { console.log(this.childMsg, 'props') console.log(this, '中间组件') } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // child本身的组件 <div class="hello"> <h1 @click='triggerClickChild'>{{$attrs}}</h1> </div>
@Component({ inheritAttrs: false }) export default class HelloWorld extends Vue { private triggerClickChild() { this.$emit('triggerClickChild', 'triggerClickChild子孙组件'); } private mounted() { console.log(this, 'attrs') // {info: '',label: '', } console.log(this.$listeners) // fn triggerClickChild } }
|
梳理以上几个组件发现这几点:
1.v-bind=’$atts’ 和 v-on=’$listeners’只能用于中间组件的传递,也就是起到承上启下的作用
2.中间组件接受的props,一旦被采用,也就无法传递到下一层。but事件,中间层阔以截胡,因为事件是由下往上,父组件和祖父组件都能接收到
3.有个弊端,如果中间层需要对数据进行二次加工,$attrs也就无用武之地,所以最好就是在顶层组件进行处理,如果处理不了就只能Props一层层传
4.当然最大的优势还是免除一层层传递,事件和属性这样简写一下高效了许多。