前言
什么叫做發(fā)布訂閱,簡單來說就是爺爺楣铁、爸爸和孫子祖孫三代的通信
現(xiàn)在有個(gè)需求癌瘾,做個(gè)tabs
image.png
image.png
思路如下所示:
image.png
首先會創(chuàng)建五個(gè)組件瓮下,它們分別是tabs(爺爺)翰铡,head(大兒子),item(大兒子的兒子們)讽坏,body(二兒子)和pane(二兒子的兒子們)
一開始item1 是亮著的锭魔,那么pane也應(yīng)該是亮著的。倘若這時(shí)候要是點(diǎn)擊了item2路呜,怎么通知到pane2呢迷捧?
第一種方法是:一開始從爺爺這通知,看紅色箭頭胀葱,這時(shí)候點(diǎn)擊ietm2,看藍(lán)色箭頭漠秋,通知head,關(guān)閉item1抵屿,在返回tabs改變selected=item2庆锦,在通知body,關(guān)閉pane1轧葛,并點(diǎn)亮pane2搂抒。(麻煩)
第二種方法就是 發(fā)爺爺艇搀、爸爸和孫子祖孫三代的通信 布訂閱
另外再做一個(gè)變量,名為EventBus求晶,當(dāng)我點(diǎn)擊了item2的時(shí)候焰雕,這時(shí)候通知EventBus,由EventBus通知tabs芳杏,更改selected=item2矩屁。點(diǎn)擊item3,方法如上蚜锨。
實(shí)例
index.html
<div id="app">
<!--<g-tabs :selected="selectedTab" @update:selected="selectedTab =$event">-->
<g-tabs :selected.sync="selectedTab" @update:selected="yyy">
<g-tabs-head>
<template slot="actions">
<button>設(shè)置</button>
</template>
<g-tabs-item name="woman">
<g-icon name="setting"></g-icon>
美女
</g-tabs-item>
<g-tabs-item name="finance" disabled>
財(cái)經(jīng)
</g-tabs-item>
<g-tabs-item name="sports">
體育
</g-tabs-item>
</g-tabs-head>
<g-tabs-body>
<g-tabs-pane name="woman">
美女相關(guān)資訊
</g-tabs-pane>
<g-tabs-pane name="finance">
財(cái)經(jīng)相關(guān)資訊
</g-tabs-pane>
<g-tabs-pane name="sports">
體育相關(guān)資訊
</g-tabs-pane>
</g-tabs-body>
</g-tabs>
</div>
tabs.vue
<template>
<div class="tabs">
<slot></slot>
</div>
</template>
<script>
import Vue from 'vue'
export default {
name: "GuLuTabs",
props: {
selected: {
type: String,
required: true, // 必須輸入 selected 這個(gè)值档插,如果沒有輸入也會在控制臺顯式報(bào)錯(cuò)
},
direction: {
type: String,
default: 'horizontal',
validator(value) {
// return ['horizontal', 'vertical'].includes(value)
return ['horizontal', 'vertical'].indexOf(value) > -1;
}
}
},
data() {
return {
eventBus: new Vue
}
},
provide() {
// 事件中心,訂閱發(fā)布
return {
eventBus: this.eventBus
}
},
mounted() {
// this.$emit('update:selected','這是一個(gè) this.$emit 出來的數(shù)據(jù)');
this.eventBus.$emit('update:selected',this.selected);
// this.$emit('update:selected','xxx')
},
created() {
this.$emit('update:selected','這是一個(gè) this.$emit 出來的數(shù)據(jù)');
this.eventBus.$emit('update:selected','this.eventBus.$emit 出來的數(shù)據(jù)');
// this.$emit('update:selected','xxx')
}
}
</script>
<style scoped lang="scss">
.tabs {
}
</style>
解析:
- 這里面的selected是選擇哪個(gè)item亚再,是必須要輸入的值郭膛,這里面的要接收前端開發(fā)者傳來的值,所以放在props中氛悬,另一點(diǎn)是required的含義是:
不允許為空则剃,必須傳值進(jìn)來
- includes 和 indexof 的區(qū)別
includes 不支持IE 傳的值是布爾型
indexof 支持IE 結(jié)果是數(shù)值 - data和props的區(qū)別
- provide()與inject
其余的子組件中必須要有 inject
開始的寫法
<script>
data() {
return {
}
},
provide() {
// 事件中心,訂閱發(fā)布
return {
eventBus: new Vue
}
},
created() {
console.log("EventBus");
this.$emit(this.eventBus);
console.log("this");
this.$emit(this);
},
</script>
在瀏覽器中運(yùn)行后如捅,發(fā)現(xiàn)打印出來的值沒有eventBus棍现,于是將new Vue
聲明在 data(){}里面
image.png
image.png
body和head的寫法
<template>
<div class="tabs-body">
<slot></slot>
</div>
</template>
<script>
export default {
name: "GuLuTabsBody",
inject: ['eventBus'],
created() {
}
}
</script>
<style scoped lang="scss">
.tabs-body {
}
</style>
----------------------------
<script>
export default {
name: "GuLuTabsHead",
inject: ['eventBus'],
created() {
}
}
</script>
item和pane的寫法
<template>
<div class="tabs-item" @click="xxx" :class="classes">
<slot></slot>
</div>
</template>
<script>
export default {
name: "GuLuTabsItem",
inject: ['eventBus'], // 不需要用戶傳值,自身維護(hù)值
data() {
return {
active: false
}
},
props: {
disabled: {
type: Boolean,
default: false
},
name: {
type: String | Number,
required: true
}
},
computed:{
classes(){
return{
active:this.active
}
}
},
created() {
this.eventBus.$on('update:selected', (name) => {
this.active = name === this.name ? true : false;
});
},
methods: {
xxx() {
this.eventBus.$emit('update:selected', this.name)
}
}
}
</script>
<style scoped lang="scss">
.tabs-item {
flex-shrink: 0; /*指定了 flex 元素的收縮規(guī)則*/
padding: 0 1em; /*用em就是不關(guān)心隔了多少像素镜遣,就關(guān)心字和字之間是否隔得開*/
&.active{
background: red;
}
}
</style>