#20 Creating A Tab Component Starting With The Tab Header
Saturday, October 19, 2019
This article will be part one in at least a two part mini-series focusing on creating a tab component. Where we left off in the last article was displaying all of the securities, categories, markets, segments, territories and types on the screen all at the same time. All of these things are related but they are distinct objects all on their own. So in order to make our app more understandable and usable we need to have a way of only showing a particular type information at one time and to do this we will be using tabs. By the end of this article we will have set up the actual tabs themselves in such a way that the active tab is highlighted and notification of which tab has been clicked will be sent to the outside tab container.
Parts
- Part 45: Adjusting Shares
- Part 44: Plan Percentages
- Part 43: Home Securities
- Part 42: Updating Plans
- Part 41: Plan Details View
- Part 40: Portfolio Getters
- Part 39: Portfolio Plan
- Part 38: Portfolio Category
- Part 37: Account Securities
- Part 36: Account Transfer
- Part 35: View Account Security
- Part 34: Updating Deposit
- Part 33: View Account Deposit
- Part 32: Display Account Details
- Part 31: Account Getters
- Part 30: Deposits And Securities
- Part 29: Add Accounts Details
- Part 28: Refactoring Accounts
- Part 27: Add Security Models
- Part 26: Edit Security Details
- Part 25: View Security Details
- Part 24: Navigating To Details
- Part 23: Getters Validation
- Part 22: Query Parameters
- Part 21: Tab Entries
- Part 20: Tab Header
- Part 19: List View
- Part 18: Vuex Getters
- Part 17: End Domain Model
- Part 16: Start Domain Model
- Part 15: Pop Routes
- Part 14: Push Routes
- Part 13: Removing Accounts
- Part 12: Vuex (Decorators)
- Part 11: Vuex (Accounts)
- Part 10: The App Bar (Settings)
- Part 9: Remove Consumer Rxjs
- Part 8: The App Bar (Back)
- Part 7: Structuring Our App
- Part 6: Animation Between Views
- Part 5: Navigation Fade
- Part 4: Navigation Requests
- Part 3: Fade Animations (cont.)
- Part 2: Fade Animations
- Part 1: Splash Screen
Code Snippets
TabHeader.vue (1:59)
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class TabHeader extends Vue {
@Prop() private readonly tabs!: string[];
}
</script>
TabHeader.vue (2:32)
<template lang="pug">
ul
li(
v-for="tab in tabs"
v-bind:key="tab")
a(href="#void") {{tab}}
</template>
TabContainer.vue (3:48)
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
import TabHeader from "@/components/tabs/TabHeader.vue";
@Component({
components: {
TabHeader,
},
})
export default class TabContainer extends Vue {
@Prop() private readonly tabs!: string[];
}
</script>
TabContainer.vue (4:37)
<template lang="pug">
div
TabHeader(v-bind:tabs="tabs")
slot
</template>
Securities.vue (5:04)
<script lang="tsx">
...
import TabContainer from "@/components/tabs/TabContainer.vue";
@Component({
components: {
...
TabContainer,
},
})
export default class Securities extends Vue {
...
private readonly tabs = [
"Securities",
"Categories",
"Markets",
"Segments",
"Territories",
"Types",
];
...
}
</script>
Securities.vue (5:43)
<template lang="pug">
TabContainer(v-bind:tabs="tabs")
ListView(
v-bind:items="securities"
v-bind:renderFn="renderFnSecurities")/
ListView(
v-bind:items="categories"
v-bind:renderFn="renderFnCategory")/
ListView(
v-bind:items="markets"
v-bind:renderFn="renderFnDescriptor('markets')")/
ListView(
v-bind:items="segments"
v-bind:renderFn="renderFnDescriptor('segments')")/
ListView(
v-bind:items="territories"
v-bind:renderFn="renderFnDescriptor('territories')")/
ListView(
v-bind:items="types"
v-bind:renderFn="renderFnDescriptor('types')")/
</template>
TabHeader.vue (6:14)
<template lang="pug">
ul.tab-headings
...
</template>
Advertisement
TabHeader.vue (6:24)
<style lang="sass">
@import "../../bitters/functions"
@import "../../bitters/variables"
$tab-border: 1px solid $light-gray
.tab-headings
display: flex
flex-wrap: wrap
border-top: $tab-border
border-left: $tab-border
li
flex: 1
text-align: center
a
display: block
padding: 0.75rem 0.5rem
text-decoration: none
border-right: $tab-border
border-bottom: $tab-border
color: $app-bar-background-color
</style>
Securities.vue (9:19)
<style lang="sass" scoped>
/deep/ .tab-headings li a
min-width: 6.3125rem
</style>
TabHeader.vue (10:56)
<script lang="ts">
...
export default class TabHeader extends Vue {
...
private click(index: number) {
this.$emit("click", index);
}
}
</script>
TabHeader.vue (13:12)
<template lang="pug">
ul.tab-headings
li(
v-for="(tab, index) in tabs"
...)
a(
...
v-on:click.prevent="click(index)") ...
</template>
TabContainer.vue (13:32)
<script lang="ts">
...
export default class TabContainer extends Vue {
...
private setActive(pos: number) {
console.log(pos);
}
}
</script>
TabContainer.vue (13:54)
<template lang="pug">
div
TabHeader(
...
v-on:click="setActive")
slot
</template>
TabHeader.vue (14:46)
<script lang="ts">
...
export default class TabHeader extends Vue {
@Prop({default: 0}) private readonly activePos!: number;
...
private activePosInternal = -1;
private get activePosition() {
return this.activePosInternal !== -1
? this.activePosInternal
: this.activePos;
}
...
private click(index: number) {
this.activePosInternal = index;
this.$emit("click", index);
}
}
</script>
TabHeader.vue (17:13)
<template lang="pug">
ul.tab-headings
li(..)
a(
...
v-bind:class="{ 'active': index===activePosition }") ...
</template>
TabHeader.vue (18:46)
<style lang="sass">
...
.tab-headings
...
a
...
&.active
background-color: $light-gray
font-weight: 600
color: $app-bar-background-color
</style>
Exciton Interactive LLC