06-xiannvmall-tabbar通用组件封装
创建一个vue项目 xiannvmall-tabbar
vue create xiannvmall-tabbar
注意: ESLint直接选默认的就好,以免出现 indent 报错
tabbar 实现思路
- 1、封装下方的tabbar组件,如何封装
- 1.1 自定义 TabBar 组件,在APP中使用
- 1.2 让 TabBar 处于页面底部,并且设置相关样式
- 2、TabBar 中小item的业务内容(图片,文字)由外部决定
- 2.1 定义插槽
- 2.2 flex布局平分 TabBar
- 3、自定义 TabBarItem, 可以传入图片和文字
- 定义TabBarItem组件,定义两个插槽,分别对应图片,文字
- 给两个插槽的外层包装一层div,用于设置样式且不会被插槽替换掉
- 填充插槽,实现底部的 TabBar效果
- 4、传入高亮图片
- 定义另外一个插槽,插入active-icon的数据
- 定义一个变量 isActiveItem, 通过v-show来决定是否显示高亮icon
- 5、TabBarItem绑定路由数据
- 安装路由: npm i vue-router -S
- 完成 router/index.js 内容,以及创建对应的组件
- main.js 中注册router
- APP中加入 router-view 路由出口标签
- 6、点击item跳转到对应路由,并且动态决定 isActiveItem
- 监听item的点击,通过this.$router.push('url') || this.$router.replace('url')//无法回到上一页
- 通过this.$route.path.indexOf(this.link) !== -1 来判断是否是 active
- 7、动态计算active样式
- 封装新的计算属性: this.isActiveItem ? {'color':'red'}:{}
tabbar组件关键代码
components/tabbar
TabBar.vue
<template>
<!-- TabBar组件 -->
<div class="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'TabBar',
}
</script>
<style scoped>
/* 给 tab-bar 弹性布局 */
.tab-bar {
display: flex;
height: 49px;
background-color: #eee;
/* 给 tabbar 固定到屏幕底端 */
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
</style>
TabBarItem.vue
<template>
<div class="tab-bar-item" @click="itemClick">
<!-- 样式和指令都要用div包裹放在div里面才行,不然就被slot替换掉没效果 -->
<div v-if="!isActiveItem === true">
<slot name="item-icon"></slot>
</div>
<div v-else>
<slot name="item-icon-active"></slot>
</div>
<div :class="{activeColor: isActiveItem}">
<slot name="item-text"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
props: {
PropPath: {
type: String,
default: ''
}
},
data() {
return {
// isActiveItem: false, // 改用计算属性 isActiveItem
}
},
computed: {
isActiveItem() {
// 浏览器 /home -> propPath="/home" = true
// 浏览器 /home -> propPath="/category" = false
// 浏览器 /home -> propPath="/cart" = false
// 浏览器 /home -> propPath="/profile" = false
// ...
return this.$route.path.indexOf(this.PropPath) !== -1 ? true : false
}
},
methods: {
itemClick() {
this.isActiveItem = true
this.$router.push(this.PropPath)
}
}
}
</script>
<style scoped>
/* 给tab-bar-item 平分区域 */
.tab-bar-item {
flex: 1;
/* 给item的文字居中 */
text-align: center;
font-size: 12px;
height: 100%;
/* 给tab-bar-item 弹性布局 主要的轴承为Y */
display: flex;
/* tab-bar-item 主轴从X改为Y,item中内容呈 上下 布局 */
flex-direction: column;
/* X轴区域内容居中 */
align-items: center;
/* Y轴区域内容居中 */
justify-content: center;
/* 盒子阴影 */
box-shadow: 0 14px 1px rgba(0, 0, 0, .1);
}
/* 给 tab-bar-item 的宽度和高度一个固定的值 */
.tab-bar-item img {
width: 24px;
height: 24px;
/* 去掉 图片的默认的margin-bottom */
vertical-align: middle;
margin-top: 3px;
margin-bottom: 2px;
}
/* 当前标题的高亮 */
.activeColor {
color: #fd5979;
}
</style>
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
// 路由懒加载
const Home = () => import('@/views/home/Home')
const Category = () => import('@/views/category/Category')
const Cart = () => import('@/views/cart/Cart')
const Profile = () => import('@/views/profile/Profile')
Vue.use(VueRouter)
const routes = [{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'Home',
component: Home,
},
{
path: '/category',
name: 'Category',
component: Category,
},
{
path: '/cart',
name: 'Cart',
component: Cart,
},
{
path: '/profile',
name: 'Profile',
component: Profile,
},
]
const router = new VueRouter({
routes,
})
export default router
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div id="app">
<!-- TabBar组件 开始-->
<tab-bar>
<!-- PropPath: tab-bar-item接受的参数props-->
<tab-bar-item PropPath="/home">
<template #item-icon>
<img src="@/assets/img/tabbar/home.svg" alt="">
</template>
<template #item-icon-active>
<img src="@/assets/img/tabbar/home_active.svg" alt="">
</template>
<template #item-text>
首页
</template>
</tab-bar-item>
<tab-bar-item PropPath="/category">
<template #item-icon>
<img src="@/assets/img/tabbar/category.svg" alt="">
</template>
<template #item-icon-active>
<img src="@/assets/img/tabbar/category_active.svg" alt="">
</template>
<template #item-text>
分类
</template>
</tab-bar-item>
<tab-bar-item PropPath="/cart">
<template #item-icon>
<img src="@/assets/img/tabbar/cart.svg" alt="">
</template>
<template #item-icon-active>
<img src="@/assets/img/tabbar/cart_active.svg" alt="">
</template>
<template #item-text>
购物车
</template>
</tab-bar-item>
<tab-bar-item PropPath="/profile">
<template #item-icon>
<img src="@/assets/img/tabbar/profile.svg" alt="">
</template>
<template #item-icon-active>
<img src="@/assets/img/tabbar/profile_active.svg" alt="">
</template>
<template #item-text>
我的
</template>
</tab-bar-item>
</tab-bar>
<!-- TabBar组件 结束-->
<!-- 路由视图出口 -->
<router-view></router-view>
</div>
</template>
<script>
import TabBar from './components/tabbar/TabBar'
import TabBarItem from './components/tabbar/TabBarItem'
export default {
name: 'App',
components: {
TabBar,
TabBarItem,
}
}
</script>
<style scoped>
@import url(assets/css/base.css);
</style>