tabbar的组件封装
对于组件的抽离,我们可以进行分析,整个下部分选项卡,肯定是可复用的,不同地方都要使用,我们将TabBar抽离成一个组件。
接下来,那么我们选项卡数目是否固定呢,内容是否固定呢,答案肯定是不,我们选项卡不能写死,也抽离出来每一个单独的,每一个选项为一个单独的item
那我如何确定它在TabBar里边有多少个item呢,那就使用插槽,预留出一个位置,开发者实际需要几个item就使用几个。
每个item其是又是图片和文字组成,我们也不能直接写死,留下具名插槽,分别对应文字和图片。
我们下标的图片肯定有两个状态,活跃和不活跃状态,那么图片传入,就用两个具名插槽,使用v-if来进行控制显示,字体也是的
TarBar.vue
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
name: "TabBar"
}
</script>
<style scoped>
#tab-bar {
display: flex;
background-color: #f6f6f6;
position: fixed;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 -3px 1px rgba(100, 100, 100, 0.2);
}
</style>
TarBarItem.vue
<template>
<div class="tab-bar-item">
<div v-if="!isActive">
<slot name="item-icon"></slot>
</div>
<div v-else>
<slot name="item-active-icon"></slot>
</div>
<div v-bind:class="{active:isActive}">
<slot name="item-text"></slot>
</div>
</div>
</template>
<script>
export default {
name: "TabBarItem",
data() {
return {
isActive:true
}
}
}
</script>
<style scoped>
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
width: 24px;
height: 24px;
margin-top: 3px;
vertical-align: middle;
margin-bottom: 2px;
}
.active {
color: red;
}
</style>
App.vue
<template>
<div id="app">
<tab-bar>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
<img slot="item-active-icon" src="./assets/img/tabbar/home_active.svg" alt="">
<div slot="item-text">首页</div>/
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="">
<img slot="item-active-icon" src="./assets/img/tabbar/category_active.svg" alt="">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/shopcart.svg" alt="">
<img slot="item-active-icon" src="./assets/img/tabbar/shopcart_active.svg" alt="">
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="">
<img slot="item-active-icon" src="./assets/img/tabbar/profile_active.svg" alt="">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from "./components/tabbar/TabBar";
import TabBarItem from "./components/tabbar/TabBarItem";
export default {
name: 'App',
components:{
TabBar,
TabBarItem
}
}
</script>
<style>
@import "./assets/css/base.css";
</style>
其实还可以将app.vue里的内容进一步抽离,这样app.vue里更加简介。
item与路由切换
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '',
redirect: '/home'
},
{
path: '/home',
component: () => import(/* webpackChunkName: "home"*/ '../views/home/Home'),
},
{
path: '/cart',
component: () => import(/* webpackChunkName: "cart"*/ '../views/cart/Cart'),
},
{
path: '/category',
component: () => import(/* webpackChunkName: "category"*/ '../views/category/Category'),
},
{
path: '/profile',
component: () => import(/* webpackChunkName: "profile"*/ '../views/profile/Profile'),
}
]
const router = new VueRouter({
routes,
mode:'history'
})
export default router
采用路由懒加载方式,注释是为了打包文件名字不采用哈希值,增加mode来设置路由方式为history模式而非hash值
我们每次点击不同的选项跳转不同的页面,不可能每个页面都写一个跳转函数,那么其实我们每个不同的按钮,都是同一个组件,那么我们直接把该组件绑定上路由跳转方法
那么不同的按钮跳转的目的路由不同,我们必须要实时接收到目的路由进行跳转,我们在app里使用的item组件,就涉及到父子组件之间通信。
子组件定义用于接受的path
props:{ path:String },
在父组件里给这个path赋值
<tab-bar-item path="/home">
不使用动态绑定的原因,原本这些路径都是固定的字符串,直接赋值给path即可,子组件自然可以接收到。
接下来就颜色问题,单击才会变色
我们不可能直接把颜色写死,哪个按钮被点击,也就是对应路由处于活跃状态,我们之前使用过父传子的path属性此刻也可以使用
item组件里设置计算属性
computed: {
isActive(){
return this.$route.path.indexOf(this.path)!==-1
}
},
$route获取的是当前活跃的路由,我们次使用item组件创建的不同按钮,其对应的path都不同,我们用活跃的路由的path,和其他所有不同组件里的path比较,哪个路由里包含这个路径,说明其处于活跃
indexOf方法是字符串查找,返回第一次出现该字符串的位置,如果没有返回-1
增加一个需求自定义文字颜色
我们有的时候颜色并不是固定的,可以根据用户选择来涉资自己的文字颜色
首先还是在item组件props里定义接受样式的对象
activeColor:{ type:String, default:'red' }
如果用户选择就是用用户颜色,否则默认红色。
然后在父组件里调用子组件时传入对应样式
<tab-bar-item path="/home" activeColor="blue">
在item里动态绑定对应样式的计算属性
activeStyle() { return this.isActive ? {color:this.activeColor}:{} }
将样式抽离成计算属性,通过判断是否活跃来设置对应的style