自定义vue底部导航栏组件tabbar
TabBar自定义vue底部导航栏组件tabbar,效果如下所示:1. 基本结构搭建根据组件封装的思想,我们事先创建几个文件夹,用来存放对应部分的代码。文件结果如下图所示:从效果图来看底部可以分为两个部分:最外层框架区和内层图标区组件就是需要的时候可以直接引用并且方便更改,那么我们就可以将tabbar导航栏组件划分为两个小的组件:TabBar.vue、TabBarItem.vueTabBar.vu
·
TabBar
自定义vue底部导航栏组件tabbar,效果如下所示:
1. 基本结构搭建
-
根据组件封装的思想,我们事先创建几个文件夹,用来存放对应部分的代码。文件结果如下图所示:
-
从效果图来看底部可以分为两个部分:最外层框架区和内层图标区
-
组件就是需要的时候可以直接引用并且方便更改,那么我们就可以将tabbar导航栏组件划分为两个小的组件:
TabBar.vue
、TabBarItem.vue
TabBar.vue
设置导航栏组件的外观形状TabBarItem.vue
负责设置内置图标汉字的样式
2. slot插槽的使用
组件里的图标和汉字我们都是不能写死的,所以就要用到<slot>
插槽对要填充内容的区域进行占位。
3. TabBar.vue
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
name: "TabBar",
}
</script>
<style scoped>
#tab-bar{
background: #f2f2f2;
display: flex;
position: fixed;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0px -1px 1px rgba(100, 100, 100, 0.2);
}
</style>
-
在
App.vue
中使用TabBar
组件的源码中,我们使用了slot插槽进行占位,那么当我们需要填充内容时,直接将内容写入<tab-bar></tab-bar>
标签里即可。
<template> <div id="app"> <tab-bar></tab-bar> </div> </template> <script> import TabBar from "./components/tabbar/TabBar" export default { name: 'App', components: { TabBar, }, } </script>
4. TabBarItem.vue
<template>
<div class="tab-bar-item" @click="itemClick">
<!-- 具名插槽 -->
<div><slot name="item-icon"></slot></div>
<div><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default {
name: "TabBarItem",
data(){
return{}
},
}
</script>
<style scoped>
.tab-bar-item{
height: 49px;
font-size: 14px;
flex: 1;
text-align: center;
}
.tab-bar-item img{
margin-top: 3px;
vertical-align: middle;
margin-bottom: 2px;
}
</style>
-
在
App.vue
中使用- 这里我只引用了一次
<tab-bar-item>
,按照需求我们是需要重复引用四次的 - 因为
TabBarItem.vue
中使用的是具名插槽,所以填入的内容也许加上对应插槽的名字,以便替换到正确的位置。
<template> <div id="app"> <tab-bar> <tab-bar-item> <img slot="item-icon" src="./assets/img/home_page.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/common.css"; </style>
- 这里我只引用了一次
5. 路由的使用
完成上面四步就能的到一个基本的框架,最后把组件跟其他页面通过路由连接起来,就能实现页面的跳转
5.1 配置路由
router.js
// 1.配置路由相关信息
import Vue from 'vue'
import VueRouter from 'vue-router'
const Home = () => import("../views/home/Home")
const Shopping = () => import('../views/shopping/Shopping')
const Sort = () => import('../views/sort/Sort')
const My = () => import('../views/my/My')
// 2. 安装路由插件
// 所有插件在使用时都要用到,Vue.use()
Vue.use(VueRouter);
// 3. 创建VueRouter对象
const routes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/shopping',
component: Shopping
},
{
path: '/sort',
component: Sort
},
{
path: '/my',
component: My
}
];
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes,
mode: 'history'
});
// 4. 将路由实例对象倒出
export default router
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router/router'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router,
}).$mount('#app')
5.2 使用路由
-
因为我们是通过点击
TabBarItem.vue
的tab-bar-item
区域,从而实现页面跳转的。那么我们可以对他进行监听- 给他绑定一个点击事件,当点击这个区域以后实现页面的跳转
<template> <div class="tab-bar-item" @click="itemClick"></div> </template>
methods:{ itemClick(){ // 当前活跃路由路径跟传过来的不一致时才进行路由跳转 if(this.$route.path != this.link){ this.$router.push(this.link); } } }
-
实现父子组件通信
-
设置
props
,在父组件App.vue
中给每一个``tab-bar-item`标签绑定路由地址,再将地址传给子组件App.vue
<template> <div id="app"> <tab-bar> <tab-bar-item link="/home" activeColor="#ff6979"> <img slot="item-icon" src="./assets/img/home_page.svg" alt=""> <img slot="item-icon-active" src="./assets/img/home-page-active.svg" alt=""> <div slot="item-text">首页</div> </tab-bar-item> </tab-bar> <!-- 视图区 --> <router-view></router-view> </div> </template>
TabBarItem.vue
export default{ name: "TabBarItem", props:{ link: String, }, }
-
6. 动态改变样式
最后我们来实现点击前后改变图片和文字的样式,点击前为黑色,点击后变为红色
-
图标点击后变红色
- 在
TabBarItem.vue
中再添加一个插槽,点击后替换掉原来那个 - 设置计算属性
isActive
,给两个图标插槽绑定v-if
和else
- 当前活跃路由路径跟传过来的一致时
isActive
为true,显示为红色
- 在
-
字体点击后变红
- 实现父子组件通信,通过
props
将activeColor
(设置字体颜色)传给父组件,在接收父组件传回的值 - 给插槽动态绑定style,设置一个计算属性
activeStyle
,如果isActive
为true则显示this.activeColor
- 实现父子组件通信,通过
-
完整代码
App.vue
<template> <div id="app"> <tab-bar> <tab-bar-item link="/home" activeColor="#ff6979"> <img slot="item-icon" src="./assets/img/home_page.svg" alt=""> <img slot="item-icon-active" src="./assets/img/home-page-active.svg" alt=""> <div slot="item-text">首页</div> </tab-bar-item> </tab-bar> <!-- 视图区 --> <router-view></router-view> </div> </template>
TabBarItem.vue
<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> <script> export default { name: "TabBarItem", props:{ link: String, activeColor:{ type: String, } }, data(){ return{ } }, computed:{ isActive(){ // 当前活跃路由路径跟传过来的是否一致 // 一致返回true return this.$route.path.includes(this.link); }, activeStyle(){ return this.isActive ? {color: this.activeColor} : {}; } }, methods:{ itemClick(){ // 当前活跃路由路径跟传过来的不一致时才进行路由跳转 if(this.$route.path != this.link){ this.$router.push(this.link); } } } } </script> <style scoped> .tab-bar-item{ height: 49px; font-size: 14px; flex: 1; text-align: center; } .tab-bar-item img{ margin-top: 3px; vertical-align: middle; margin-bottom: 2px; } </style>
更多推荐
已为社区贡献4条内容
所有评论(0)