1. 項目初始:
新建tabs.vue/tabs-body.vue/tabs-head.vue/tabs-item.vue/tabs-pane.vue
樣式結構
tabs.vue
<template>
<div class="tabs">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'GuluTabs',
props: {
selected: {
type: String
}
},
created(){
}
}
</script>
<style lang="scss" scoped>
.tabs{
}
</style>
app.js
new Vue({
el: '#app',
data: {
selectedTab: 'sports'
}
})
index.html
<div id="app">
<!--selected就是默認一開始選中的tab項厘肮,當你點擊每個tab的時候需要更改selected的值,也就是更改selectedTab橡疼,這里需要使用@update:selected="selectedTab = $event"譬猫,使用vue語法糖聋亡,可以寫成下面的-->
<g-tabs :selected.sync="selectedTab">
<!--等價于<g-tabs :selected="selectedTab" @update:selected = "selectedTab = $event">-->
<g-tabs-head>
<g-tabs-item name="woman">
美女
</g-tabs-item>
<g-tabs-item name="finance">
財經(jīng)
</g-tabs-item>
<g-tabs-item name="sports">
體育
</g-tabs-item>
</g-tabs-head>
<g-tabs-body>
<g-tabs-pane name="woman">
美女相關資訊
</g-tabs-pane>
<g-tabs-pane name="finance">
財經(jīng)相關資訊
</g-tabs-pane>
<g-tabs-pane name="sports">
體育相關資訊
</g-tabs-pane>
</g-tabs-body>
</g-tabs>
</div>
相關補充:
$event
是指對應的事件信息茅郎。
對于原生元素(如 button泛源、input)來說篙挽,$event
是原始的 DOM 事件冲秽。
對于自定義組件(如 child)來說舍咖,$event
是其自身$emit
里的第二個參數(shù)。
上面的$event
就是$emit
的第二個參數(shù)锉桑,也就相當于$emit('update:selceted', 'xxx')
排霉,也就是update:selected事件觸發(fā)時你寫的第二個參數(shù)就比如我這里的'xxx',那么你的$event就是'xxx'民轴,其實就是子組件給父組件傳遞的那個數(shù)據(jù)就相當于
index.html
<g-tabs @update:selected="add">
</g-tabs>
<g-tabs @update:selected="selectedTab=$event">
{{selectedTab}}//這里的值就是$event也就是你下面觸發(fā)update:selected事件傳入的數(shù)據(jù)'xxx'
</g-tabs>
<script>
var app = new Vue({
data: {
selectedTab: ''
},
methods: {
//這里的value就是子組件傳遞來的數(shù)據(jù)攻柠,也就是$event,也就是當你在子組件觸發(fā)父組件的事件的時候后裸,$event就是你在子組件觸發(fā)事件時傳入的數(shù)據(jù)(也就是第二個參數(shù))
add(value){
console.log(value)//xxx
}
}
})
</script>
子組件tabs.vue
<template>
<div class="tabs">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'GuluTabs',
created(){
this.$emit('update:selected', 'xxx')
}
}
</script>
實現(xiàn)tab切換
通過事件中心發(fā)布訂閱給所有的組件瑰钮,誰變了就發(fā)布一個事件,其他的組件跟著訂閱就好
在tabs.vue組件中聲明一個事件中心
import Vue from 'vue'
export default {
name: 'GuluTabs',
data(){
return {
eventBus: new Vue()
}
},
provide(){
return {
eventBus: this.eventBus
}
},
created(){
console.log(this.eventBus)
//this.$emit('update:selected', $event.tagrget)
}
}
在data里聲明這個eventBus微驶,然后通過provide(https://cn.vuejs.org/v2/api/#provide-inject)方法將當前的eventBus傳給eventBus好讓其他的組件都可以使用浪谴,然后哦當前組件只需要通過this.eventBus就可以使用开睡,這里通過proviede方法提供的屬性,在其他任何子孫組件中可以直接通過inject['eventBus']注入苟耻,然后只要在其他組件中使用this.eventBus就可以拿到這個事件中心了篇恒,然后只需要在每個組件的事件中心里觸發(fā)你的update:selcected事件,將它們的name就可以拿到它們對應的name了
在tabs-item和tabs-pane組件中分別監(jiān)聽事件中心的update:selected事件凶杖,當點擊tabs-item的時候觸發(fā)這個事件胁艰,并把當前name傳給組件
tabs-item.vue
<template>
<div class="tabs-item" @click="xxx">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'GuluItem',
props: {
disabled: {
type: Boolean,
default: false
},
name: {
type: String | Number,
required: true
}
},
inject: ['eventBus'],
created(){
this.eventBus.$on('update:selected',(name)=>{
console.log(name)
})
},
methods: {
xxx(){
this.eventBus.$emit('update:selected',this.name)
}
}
}
</script>
tabs-pane.vue
<template>
<div class="tabs-pane">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'GuluPane',
inject: ['eventBus'],
created(){
this.eventBus.$on('update:selected',(name)=>{
console.log(name)
})
}
}
</script>
然后點擊tabs-item就會打印出6個對應的name,上面三個item和下面三個pane的
- 問題1:我通過事件中心觸發(fā)了update:selected事件智蝠,那會不會觸發(fā)下面的yyy腾么?
index.html
<g-tabs @update:selected="yyy">
</g-tabs>
<script>
var app = new Vue({
methods: {
yyy(value){
console.log(value)
}
}
})
</script>
答:不會。因為你的事件中心eventBus是在tabs.vue里的data里聲明的一個new Vue()杈湾,而你上面的代碼<g-tabs @update:selected="yyy">
是監(jiān)聽的<g-tabs>解虱,也就是組件tabs,當tabs觸發(fā)update:selected事件時毛秘,他才會執(zhí)行yyy饭寺,要想觸發(fā)tabs組件的update:selected事件阻课,就要直接在tabs.vue里寫
created(){
this.$emit('update:selected', '這是this $emit出來的數(shù)據(jù)')
}
然后yyy就會執(zhí)行叫挟,就會打印出這是this $emit出來的數(shù)據(jù)
- 問題2:我如果在<g-tabs-head>里觸發(fā)update:selected事件,那么<g-tabs>里的yyy會被觸發(fā)嗎限煞?
index.html
<g-tabs @update:selected="yyy">
<g-tabs-head>
<g-tabs-head>
</g-tabs>
tabs-head
created(){
this.$emit('update:selected','這是tabs-head拋出的數(shù)據(jù)')
}
答:不會抹恳。原因vue的事件是不會冒泡的,你在哪個組件上觸發(fā)事件署驻,就要對應的在哪個組件對應的標簽上監(jiān)聽事件奋献。
切換功能實現(xiàn)
在tabs.vue里觸發(fā)事件中心將當前的selected傳給組件
<template>
<div class="tabs">
<slot></slot>
</div>
</template>
<script>
import Vue from 'vue'
export default {
name: 'GuluTabs',
props: {
selected: {
type: String,
required: true
},
direction: {
type: String,
default: 'horizontal',
validator(value){
return ['horizontal', 'vertical'].indexOf(value) >=0
}
}
},
data(){
return {
eventBus: new Vue()
}
},
provide(){
return {
eventBus: this.eventBus
}
},
mounted(){
//用來初始化的時候
this.eventBus.$emit('update:selected', this.selected)
}
}
</script>
然后在item和pane里監(jiān)聽事件中心,拿到事件觸發(fā)時傳入的selceted旺上,如果當前的name等于傳進來的selecetd就讓active為true
tabs-item.vue
<template>
<div class="tabs-item" @click="xxx" :class="{active:active}">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'GuluItem',
props: {
disabled: {
type: Boolean,
default: false
},
name: {
type: String | Number,
required: true
}
},
data(){
return {
active: false
}
},
inject: ['eventBus'],
created(){
this.eventBus.$on('update:selected',(name)=>{
if(this.name === name){
this.active = true
}else{
this.active = false
}
})
},
methods: {
//每次點擊對應的tab將當前的name傳給事件
xxx(){
this.eventBus.$emit('update:selected',this.name)
}
}
}
</script>
<style lang="scss" scoped>
.tabs-item {
flex-shrink: 0;
padding: 0 2em;
&.active{
background: red;
}
}
</style>
tabs-pane.vue
<template>
<div class="tabs-pane" v-show="active" :class="{active:active}">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'GuluPane',
inject: ['eventBus'],
data(){
return {
active: false
}
},
props: {
name: {
type: String | Number,
required: true
}
},
created(){
this.eventBus.$on('update:selected',(name)=>{
if(this.name === name){
this.active = true
}else{
this.active = false
}
})
}
}
</script>
<style lang="scss" scoped>
.tabs-pane{
&.active{
background: red;
}
}
</style>