封装TabBar案例
TabBar.png
通过学习上面这个TabBar的封装,感受一下组件化开发和封装的思想。
一、第一步
先写死,就写4个条目,分别是首页,分类,购物车,我的,先写在Vue.app中,把tab-bar的css样式和tab-bar-item的样式调整好
<template>
<div id="app">
<div id="tab-bar">
<div class="tab-bar-item">
<img src="./assets/img/tabbar/home.svg" alt="...">
<div class="item-text">首页</div>
</div>
<div class="tab-bar-item">
<img src="./assets/img/tabbar/category.svg" alt="...">
<div class="item-text">分类</div>
</div>
<div class="tab-bar-item">
<img src="./assets/img/tabbar/shopcart.svg" alt="...">
<div class="item-text">购物车</div>
</div>
<div class="tab-bar-item">
<img src="./assets/img/tabbar/profile.svg" alt="...">
<div class="item-text">我的</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
/* 在style中引用文件这样子使用@import + url */
@import './assets/css/base.css';
#tab-bar{
/* 流体布局,使得这个元素占据一行 */
display: flex;
height: 49px;
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #f6f6f6;
font-size: 14px;
/*
<length>①: 第 1 个长度值定义元素的阴影水平偏移值。正值,阴影出现在元素右侧;负值,则阴影出现在元素左侧
<length>②: 第 2 个长度值定义元素的阴影垂直偏移值。正值,阴影出现在元素底部;负值,则阴影出现在元素顶部
<length>③: 第 3 个长度值定义元素的阴影模糊值半径(如果提供了)。该值越大阴影边缘越模糊,若该值为0,阴影边缘不出现模糊。不允许负值 <length>④: 第 4 个长度值定义元素的阴影外延值(如果提供了)。正值,阴影将向四面扩展;负值,则阴影向里收缩
<color>: 定义元素阴影的颜色。如果该值未定义,阴影颜色将默认取当前最近的文本颜色 inset: 定义元素的阴影类型为内阴影。该值为空时,则元素的阴影类型为外阴影
*/
box-shadow: 0 -3px 1px rgba(100,100,100,.08);
}
.tab-bar-item{
/* 使得这些元素均等分布在流体元素中 */
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
/* 使得图片下面不要离文字太远 */
/* middle: 把当前盒的垂直中心和父级盒的基线加上父级的半x-height对齐 */
vertical-align: middle;
}
</style>
第二步、把tab-bar抽成一个独立的组件
TabBar组件
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
name:"TabBar"
}
</script>
<style scoped>
#tab-bar{
display: flex;
height: 49px;
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #f6f6f6;
font-size: 14px;
box-shadow: 0 -3px 1px rgba(100,100,100,.08);
}
</style>
第三步、将TabBar中的每个条目抽成一个独立的组件tab-bar-item
tab-bar-item组件
<template>
<div class="tab-bar-item">
<div v-if="isActive"><slot name="item-icon-active"></slot></div>
<div v-else><slot name="item-icon"></slot></div>
<div class="item-text">
<slot name="item-text"></slot>
</div>
</div>
</template>
<script>
export default {
name:"TabBarItem",
data(){
return {
isActive:false
}
}
}
</script>
<style scoped>
.tab-bar-item{
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
vertical-align: middle;
}
</style>
第四步、在进行完上面两步后,现在的App.vue长这样
<template>
<div id="app">
<tab-bar>
<tab-bar-item>
<img src="./assets/img/tabbar/home.svg" alt="..." slot="item-icon">
<img src="./assets/img/tabbar/home_active.svg" alt="..." slot="item-icon-active">
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item>
<img src="./assets/img/tabbar/category.svg" alt="..." slot="item-icon">
<img src="./assets/img/tabbar/category_active.svg" alt="..." slot="item-icon-active">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item>
<img src="./assets/img/tabbar/shopcart.svg" alt="..." slot="item-icon">
<img src="./assets/img/tabbar/shopcart_active.svg" alt="..." slot="item-icon-active">
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item>
<img src="./assets/img/tabbar/profile.svg" alt="..." slot="item-icon">
<img src="./assets/img/tabbar/profile_active.svg" alt="..." slot="item-icon-active">
<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>
/* 在style中引用文件这样子使用@import + url */
@import './assets/css/base.css';
</style>
第五步、配置路由
import Vue from 'vue'
import Router from 'vue-router'
//使用懒加载来导入组件
const Home = () => import('../components/Home')
const Category = () => import('../components/Category')
const Profile = () => import('../components/Profile')
const ShopCart = () => import('../components/ShopCart')
//1.注入插件
Vue.use(Router)
//2.创建路由配置对象
const routes = [
{
path:'',
//默认显示首页,重定向
redirect:'/home'
},
{
path:'/home',
component:Home
},
{
path:'/category',
component:Category
},
{
path:'/shopCart',
component:ShopCart
},
{
path:'/profile',
component:Profile
}
]
export default new Router({
routes,
//使用H5的history模式改变url
mode:'history'
})
第六步、通过代码跳转路由,设置活跃时候的字体颜色可由外界传入
<template>
<div class="tab-bar-item" @click="itemClick">
<div v-if="isActive"><slot name="item-icon-active"></slot></div>
<div v-else><slot name="item-icon"></slot></div>
<div class="item-text" :style="finalColor">
<slot name="item-text"></slot>
</div>
</div>
</template>
<script>
export default {
name:"TabBarItem",
data(){
return {
}
},
props:{
path:{
type:String,
require:true
},
color:{
type:String,
default:"red"
}
}
,
computed:{
isActive(){
return this.$route.path.indexOf(this.path) !== -1;
},
finalColor(){
return this.isActive?{color:this.color}:{};
}
},
methods:{
itemClick(){
// 判断是否正处于活跃状态,若是的话不进行跳转
this.$route.path.indexOf(this.path) !== -1?void(0):this.$router.replace(this.path);
}
}
}
</script>
<style scoped>
.tab-bar-item{
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
vertical-align: middle;
}
</style>
第七步、将最终的TabBar抽成组件,使得App中的代码减少
<template>
<div>
<tab-bar>
<tab-bar-item path='/home' color="deepPink">
<img src="@/assets/img/tabbar/home.svg" alt="..." slot="item-icon">
<img src="@/assets/img/tabbar/home_active.svg" alt="..." slot="item-icon-active">
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item path='/category' color="deepPink">
<img src="@/assets/img/tabbar/category.svg" alt="..." slot="item-icon">
<img src="@/assets/img/tabbar/category_active.svg" alt="..." slot="item-icon-active">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path='/shopCart' color="deepPink">
<img src="@/assets/img/tabbar/shopcart.svg" alt="..." slot="item-icon">
<img src="@/assets/img/tabbar/shopcart_active.svg" alt="..." slot="item-icon-active">
<div slot="item-text">购物车</div>
</tab-bar-item >
<tab-bar-item path='/profile' color="deepPink">
<img src="@/assets/img/tabbar/profile.svg" alt="..." slot="item-icon">
<img src="@/assets/img/tabbar/profile_active.svg" alt="..." slot="item-icon-active">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from './TabBar'
import TabBarItem from './TabBarItem'
export default {
name:"FinalTabBar",
components:{
TabBar,
TabBarItem
}
}
</script>
<style scoped>
</style>
到了这里,基本的功能差不多实现了,不过,我注意到一点,就是频繁的复制粘贴代码片段的时候,其中的一些涉及到路径的东西很容易出问题,因为写的是相对路径,所以为了使代码更加强壮,可移植性更强,我们应该把路径从src开始写起,但是一个个都这样的话代码量太大了,而且没什么意义,所以我们可以给路径改名
第八步、路径改别名
在使用Vue/CLI2.xc创建的项目中,可以打开build/webpack.base.conf.js文件,找到这里进行路径改别名
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
}
},
现在@已经映射了src了,我们可以继续添加一些别名
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
'assets':resolve('src/assets'),
'components':resolve('src/components'),
'views':resolve('src/components/views')
}
},
注意:使用别名的时候有两种情况
-
在import或者require 中使用别名
这时候直接写别名就可以了
-
在其它情况下使用别名
这时候在别名前面要加一个"~"
使用别名后
<template> <div> <tab-bar> <tab-bar-item path='/home' color="deepPink"> <img src="~assets/img/tabbar/home.svg" alt="..." slot="item-icon"> <img src="~assets/img/tabbar/home_active.svg" alt="..." slot="item-icon-active"> <div slot="item-text">首页</div> </tab-bar-item> <tab-bar-item path='/category' color="deepPink"> <img src="~assets/img/tabbar/category.svg" alt="..." slot="item-icon"> <img src="~assets/img/tabbar/category_active.svg" alt="..." slot="item-icon-active"> <div slot="item-text">分类</div> </tab-bar-item> <tab-bar-item path='/shopCart' color="deepPink"> <img src="~assets/img/tabbar/shopcart.svg" alt="..." slot="item-icon"> <img src="~assets/img/tabbar/shopcart_active.svg" alt="..." slot="item-icon-active"> <div slot="item-text">购物车</div> </tab-bar-item > <tab-bar-item path='/profile' color="deepPink"> <img src="~assets/img/tabbar/profile.svg" alt="..." slot="item-icon"> <img src="~assets/img/tabbar/profile_active.svg" alt="..." slot="item-icon-active"> <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:"FinalTabBar", components:{ TabBar, TabBarItem } } </script> <style scoped> </style>
对配置文件进行修改之后一定要重新跑一下项目才会生效