目标:
希望用户如下使用代码:
<m-tabs>
<m-tabs-nav>
<m-tabs-item name="tab1"></m-tabs-item>
<m-tabs-item name="tab2"></m-tabs-item>
</m-tabs-nav>
<m-tabs-content>
<m-tabs-pane name="tab1"></m-tabs-pane>
<m-tabs-pane name="tab2"></m-tabs-pane>
</m-tabs-content>
</m-tabs>
接下来我们就来创建5个组件
思路分析:
爷爷组件tabs 有数据 selectedTag, 然后会向head和Body传值,然后,head会向自己的三个孩子传值,body会向自己的三个孩子传值
这里我们可以用到provide和inject
provide 选项允许我们指定我们想要提供给后代组件的数据/方法
然后在任何后代组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的 property.
由于爷爷、爸爸、孙子三者之间的信息传递较为复杂,我们选择用eventbus来减少复杂
用new Vue()做EventBus
如果一个对象可以on, $off就是一个eventBus
Tab.vue
@Component
export default class Tab extends Vue {
...
eventBus = new Vue();
@Provide('eventbus') eventbus: Vue = this.eventBus;
}
爷爷provide, 然后儿子、孙子里inject
@Component
export default class TabHead extends Vue {
@Inject() eventbus!: Vue;
created(){
console.log('爷爷给爸爸的eventBus')
console.log(this.eventbus)
}
}
@Component
export default class TabItem extends Vue {
@Inject() eventbus!: Vue;
@Prop(String) name: string | undefined;
created() {
console.log("爷爷给tab item的eventbus")
console.log(this.eventBus)
this.eventbus.$on('update:selected', (name: string) => {
console.log(name);
});
}
}
到底是谁在触发,谁在监听?
this.$emit 是当前实例在触发
this.eventBus.$emit 是eventBus这个对象本身在触发,注意两者的区别
在vue中,事件并不会冒泡,我们需要关注是在哪个对象上触发的事件
问题一:
<m-tabs @update:selected="yyy">
<m-tabs-nav>
<m-tabs-item name="tab1"></m-tabs-item>
<m-tabs-item name="tab2"></m-tabs-item>
</m-tabs-nav>
<m-tabs-content>
<m-tabs-pane name="tab1"></m-tabs-pane>
<m-tabs-pane name="tab2"></m-tabs-pane>
</m-tabs-content>
</m-tabs>
组件之间用eventBus触发和监听事件,那么爷爷上的@update:selected="yyy"事件会被触发吗?
答案是不会!因为eventBus触发的事件和这个组件没有关系
问题二:
<m-tabs @update:selected="yyy">
<m-tabs-nav>
<m-tabs-item name="tab1"></m-tabs-item>
<m-tabs-item name="tab2"></m-tabs-item>
</m-tabs-nav>
<m-tabs-content>
<m-tabs-pane name="tab1"></m-tabs-pane>
<m-tabs-pane name="tab2"></m-tabs-pane>
</m-tabs-content>
</m-tabs>
如果在上触发同名事件@update:selected,请问爷爷组件上的@update:selected事件会被触发吗?
答案是不会,在vue里事件是不会冒泡的
小结:
- 在哪个对象触发事件,就在那个对象上监听
- vue里事件不会冒泡
Props传值还是Data传值?
props: 需要用户传值
data不需要用户传值,自身维护
我们这里用data来传值
切换tag
实现切换tag功能有两步
第一步是从外界取值
点击一个tag后,爷爷组件会广而告之所有人,XXX被选中了,然后他的孙子们通过eventBus就能知道了!
然后我们根据传进来的变量,计算出css class, 然后更新样式
Tab组件(爷爷组件)
@Provide('eventbus') eventbus: Vue = this.eventBus;
mounted() {
this.eventbus.$emit('update:selected', this.selected);
}
TabPanel 和 TabItem
created() {
this.eventbus.$on('update:selected', (name: string) => {
this.active = name === this.name;
});
}
孙子组件在created阶段就开始监听'update:selected'事件,然后判断被选中的是不是自己
第二步是用点击事件从内部更新
因为vue里事件不会冒泡,所以我们监听点击元素:tab-item, 设置onClick事件
TabItem
<template>
<div class="tab-item" @click="xxx" :class="classes">
<slot></slot>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import {Component, Inject, Prop} from 'vue-property-decorator';
@Component
export default class TabItem extends Vue {
@Inject() eventbus!: Vue;
@Prop(String) name: string | undefined;
@Prop(Boolean) disabled = false;
active = false;
get classes() {
return {
active: this.active
};
}
created() {
this.eventbus.$on('update:selected', (name: string) => {
this.active = name === this.name;
});
}
xxx() {
this.eventbus.$emit('update:selected', this.name, this)
}
}
每次点击,就往事件中心广播 是哪个Name被点击了
本文为fjl的原创文章,著作权归本人和饥人谷所有,转载务必注明来源