MainTabBar组件在软件下方展示了四个主选项卡:首页(Home)、分类(Category)、购物车(Cart)、我的(Profile),每个选项对应一个页面、一个组件。总体来看,MainTabBar可以看做由一个容器+若干个item组成,所以我们把单个item看做一个组件,把容器看作另一个组件,然后在MainTabBar组件中使用它们,最后在App.vue中使用MainTabBar。(因为无论路由切换到哪里,MainTabBar始终会被显示。)
首先来看单个item对应的组件tabBarItem。按照惯例,每个item应该包含小图标+下方文字即可,不过我们这里为每个item准备了两个小图标(另一张是当前item被选中时的高亮颜色版本)。由于使用什么图片、什么文字需要在使用时决定,所以把它们全部设为具名插槽:
<template> <div class="tab-bar-item" @click="itemClick"> <div v-if="!isActive"><slot name="item-icon"></slot></div> <div v-else><slot name="item-icon-active"></slot></div> <div :style="activeStyle"><slot name="item-text"></slot></div> </div> </template>
使用tabBarItem组件:
<tab-bar-item path="/home"> <img slot="item-icon" src="~assets/img/tabbar/home.svg" > <img slot="item-icon-active" src="~assets/img/tabbar/home_active.svg" > <div slot="item-text">首页</div> </tab-bar-item>
当某个选项被点击后,会触发itemClick方法,所以最直接的效果就是当前路由被替换成被点击选项对应的路由,即path属性,该属性于每个tabBarItem被创建时从外部传入,值分别为“/home”、“/category”、“/cart”和“/profile”。
itemClick() { this.$router.replace(this.path) }
此外,被点击的选项也会发生一些变化——
1、切换高亮图标,通过v-if和v-else来实现,isActive默认为false,此时显示普通图标,如果isActive变为true则切换高亮图标。isActive是一个计算属性,如果this.$router.path中包含this.path,说明当前选项对应的页面被显示,则把isActive置为true。
isActive() { return this.$route.path.indexOf(this.path) !== -1 }
2、改变字体颜色,通过动态添加style来实现。
activeStyle() { return this.isActive ? {color: this.activeColor} : {} }
高亮后的颜色也可以设为动态的,在使用时指定,这样每个item点击后可以显示不同的颜色。
props: { path: String, activeColor: { type: String, default: ‘red‘ } }
接下来的容器组件TabBar比较简单,它无需任何js代码,只需要提供一个插槽,然后给插槽外部套的div设置弹性容器属性以及fixed定位。(因为滚动对TabBar的位置没有影响。)
<template> <div id="tab-bar"> <slot></slot> </div> </template>
第三步,在包装组件MainTabBar(自己取得名字,因为它没有什么特殊功能,只是因为使用上面两个组件的代码太多,为了防止App.vue太臃肿,才多加了这么一层。)中注册并使用这两个组件,在TabBar中插入tabBarItem,在每个tabBarItem中插入图标和文字。
<template> <tab-bar> <tab-bar-item path="/home"> <img slot="item-icon" src="~assets/img/tabbar/home.svg" alt=""> <img slot="item-icon-active" src="~assets/img/tabbar/home_active.svg" alt=""> <div slot="item-text">首页</div> </tab-bar-item> ... </tab-bar> </template>
最后,在App.vue中注册并使用MainTabBar。
<template> <div id="app"> <keep-alive exclude="Detail"> <router-view></router-view> </keep-alive> <main-tab-bar></main-tab-bar> </div> </template>