目录
阶段案例:TabBar
如果在下方有一个单独的 TabBar 组件,你如何封装?
效果图:
实现思路
首先自定义 TabBar 组件。在 APP 中使用,让 TabBar 位于底部,并且设置相关的样式。TabBar 中显示的内容由外界决定。定义插槽,flex 布局平分 TabBar。
其次自定义 TabBarItem 组件,可以传入图标和文字。定义 TabBarItem,并且定义图标、文字两个插槽。给两个插槽外层包装 div,用于设置样式。填充插槽,实现底部 TabBar 的效果。
代码实现
先创建名为 tabbar 的项目(选择自定义,添加路由)。
vue create tabbar
把准备好的静态资源图标和基本样式放在项目里。
|- /assets
+ |- /css
| - base.css // 基本样式
+ |- /font // 这里使用iconfont字体图标
| - iconfont.css
| - iconfont.ttf
src/assets/css/base.css
body {
padding: 0;
margin: 0;
}
/* 活动路由 class */
.active {
color: #aa0000;
}
/* 图标字体大小 */
.iconfont {
font-size: 20px;
}
创建四个视图组件。
src/views/Home.vue
<template>
<div class="home">
<h1>This is an home page</h1>
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
<style>
</style>
src/views/Category.vue
<template>
<div class="category">
<h1>This is an category page</h1>
</div>
</template>
<script>
export default {
name: "Category"
}
</script>
<style>
</style>
src/views/ShoppingCart.vue
<template>
<div class="shopping-cart">
<h1>This is an shopping cart page</h1>
</div>
</template>
<script>
export default {
name: "ShoppingCart"
}
</script>
<style>
</style>
src/views/Mine.vue
<template>
<div class="mine">
<h1>This is an mine page</h1>
</div>
</template>
<script>
export default {
name: "Mine"
}
</script>
<style>
</style>
配置路由。
src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/category',
name: 'Category',
component: () => import('../views/Category.vue')
},
{
path: '/shoppingCart',
name: 'ShoppingCart',
component: () => import('../views/ShoppingCart.vue')
},
{
path: '/mine',
name: 'Mine',
component: () => import('../views/Mine.vue')
}
]
const router = new VueRouter({
routes,
// 配置活动路由 class
linkActiveClass: 'active'
})
export default router
创建 TabBar 和 TabBarItem 组件。
src/components/tabbar/TabBarItem .vue
<template>
<div class="tab-bar-item">
<!-- 路由组件,绑定当前组件的 path 属性,编译成 div 标签 -->
<router-link :to="path" tag="div">
<!-- 非活动路由状态下,图标命名插槽 -->
<slot v-if="!isActive" name="item-icon"></slot>
<!-- 活动路由状态下,图标命名插槽 -->
<slot v-else name="item-icon-active"></slot>
<!-- 文字命名插槽 -->
<slot name="item-title"></slot>
</router-link>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
props: {
path: {
type: String,
required: true
}
},
computed: {
isActive() {
// 计算属性,当前路由是否处于活动的状态,显示不同的图标
return this.$route.path.indexOf(this.path) !== -1
}
}
}
</script>
<style scoped>
/* 本身样式 */
.tab-bar-item {
flex: 1;
text-align: center;
height: 40px;
font-size: 12px;
margin-top: 10px;
}
</style>
src/components/tabbar/TabBar .vue
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
name: "TabBar"
}
</script>
<style scoped>
/* 本身样式 */
#tab-bar {
background-color: #F1F1F1;
box-shadow: 0 -1px 1px rgba(100,100,100,.2);
font-size: 14px;
/* 使用 flex 进行布局 */
display: flex;
/* 定位相关 */
position: fixed;
left: 0;
right: 0;
bottom: 0;
}
</style>
修改 App.vue
<template>
<div id="app">
<router-view></router-view>
<tab-bar>
<!-- 首页 -->
<tab-bar-item path="/home">
<template #item-icon>
<div class="iconfont icon-shouye-xianxing"></div>
</template>
<template #item-icon-active>
<div class="iconfont icon-shouye-mianxing"></div>
</template>
<template #item-title><div>首页</div></template>
</tab-bar-item>
<!-- 分类 -->
<tab-bar-item path="/category">
<template #item-icon>
<div class="iconfont icon-fenlei-xianxing"></div>
</template>
<template #item-icon-active>
<div class="iconfont icon-fenlei-mianxing"></div>
</template>
<template #item-title><div>分类</div></template>
</tab-bar-item>
<!-- 购物车 -->
<tab-bar-item path="/shoppingCart">
<template #item-icon>
<div class="iconfont icon-gouwuche-xianxing"></div>
</template>
<template #item-icon-active>
<div class="iconfont icon-gouwuche-mianxing"></div>
</template>
<template #item-title><div>购物车</div></template>
</tab-bar-item>
<!-- 我的 -->
<tab-bar-item path="/mine">
<template #item-icon>
<div class="iconfont icon-wode-xianxing-1"></div>
</template>
<template #item-icon-active>
<div class="iconfont icon-wode-mianxing-1"></div>
</template>
<template #item-title><div>我的</div></template>
</tab-bar-item>
</tab-bar>
<!--
<div id="tab-bar">
<div class="tab-bar-item active">
<div class="iconfont icon-shouye-mianxing"></div>
<div>首页</div>
</div>
<div class="tab-bar-item">
<div class="iconfont icon-fenlei-xianxing"></div>
<div>分类</div>
</div>
<div class="tab-bar-item">
<div class="iconfont icon-gouwuche-xianxing"></div>
<div>购物车</div>
</div>
<div class="tab-bar-item">
<div class="iconfont icon-wode-xianxing-1"></div>
<div>我的</div>
</div>
</div>-->
</div>
</template>
<script>
// 导入 TabBar 和 TabBarItem 俩个组件
import TabBar from './components/tabbar/TabBar.vue'
import TabBarItem from './components/tabbar/TabBarItem.vue'
export default {
name: "App",
components: {
TabBar,
TabBarItem
}
}
</script>
<style>
/* 导入基本样式 */
@import url("assets/css/base.css");
/* 导入iconfont字体图标 */
@import url("assets/font/iconfont.css");
</style>
这里为大家提供该案例中 iconfont 字体图标在线链接:
@import url("//at.alicdn.com/t/font_2543261_qfljvc23ga.css");