Vue.js 2.0 Tabs (inline)
Vue.js 2.0 Tabs
by Michael Menaker
HTML
<div id="app">
<tabs>
<tab title="A">
<p>Content A</p>
</tab>
<tab title="B">
<div>
<p>Content B</p>
</div>
</tab>
<tab title="C" v-bind:is-active="true">
<p>Content C</p>
</tab>
</tabs>
</div>
<template id="tabs">
<div class="tabs">
<ul>
<li v-for="tab in tabs" v-bind:class="{'active': current === tab}" @click="changeTab(tab)">
{{tab.title}}
</li>
</ul>
<slot></slot>
</div>
</template>
<template id="tab">
<transition :name="slideType" @after-leave="afterLeave">
<div v-show="active" :class="{'active': active}">
<slot></slot>
</div>
</transition>
</template>
CSS
.tabs > ul {
overflow: hidden;
font: bold 10px Verdana, sans-serif;
margin: 0;
padding: 0;
padding-bottom: 10px;
}
.tabs > ul li {
float: left;
list-style: none;
background: #ddd;
border: 1px solid #f5f7fa;
color: #666;
cursor: pointer;
display: block;
padding: 0 30px;
text-decoration: none;
border-top: 1px solid #ddd;
}
.tabs > ul li:hover {
background: #eee;
text-decoration: none;
}
.tabs > ul li.active {
color: #333;
background: #f5f7fa;
}
.slide-left-leave-active,
.slide-left-enter-active,
.slide-right-leave-active,
.slide-right-enter-active {
transition: .5s;
}
.slide-left-enter {
transform: translate(20%, 0);
}
.slide-left-leave-to {
transform: translate(-20%, 0);
}
.slide-right-enter {
transform: translate(-20%, 0);
}
.slide-right-leave-to {
transform: translate(20%, 0);
}
JavaScript
Vue.component('tabs', {
template: '#tabs',
data: function() {
return {
tabs: [],
current: null
};
},
methods: {
addTab: function(tab) {
this.tabs.push(tab);
if (tab.active === true) {
this.current = tab;
}
},
changeTab(tab) {
const slideType = this.getSlideType(tab);
this.deactivateTab(slideType);
this.setCurrent(tab, slideType);
},
deactivateTab(slideType) {
this.current.slideType = slideType;
this.current.active = false;
},
setCurrent(tab, slideType) {
this.current = tab;
this.current.slideType = slideType;
},
activateTab() {
this.current.active = true;
},
getSlideType(tab) {
const newTabIndex = this.tabs.indexOf(tab);
const oldTabIndex = this.tabs.indexOf(this.current);
return newTabIndex > oldTabIndex ? "slide-left" : "slide-right";
}
}
});
Vue.component('tab', {
template: '#tab',
data: function() {
return {
active: false,
slideType: "slide-left"
};
},
props: {
'title': {
required: true,
type: String
},
'isActive': {
required: false,
type: Boolean,
default: false
}
},
created: function() {
this.active = this.isActive;
},
mounted: function() {
this.$parent.addTab(this);
},
methods: {
afterLeave() {
this.$parent.activateTab();
}
}
});
var app = new Vue({
el: '#app',
data: {}
});