TabBar实例练习
跟着视频做的一个小demo
代码连接:
链接:https://pan.baidu.com/s/14qAgi-ZADsXXn5YhPh5O7Q
提取码:rt3n
1.新建一个vuecli2-tabbar实例
2.先搭建最基本的框架
主页文字包括:首页、分类、购物车、我的。这几个持水平分布
在App.vue
文件中导入基本的组件:
<template>
<div id="app">
<div id="tab-bar">
<div class="tab-bar-item">首页</div>
<div class="tab-bar-item">分类</div>
<div class="tab-bar-item">购物车</div>
<div class="tab-bar-item">我的</div>
</div>
</div>
</template>
样式直接在App.vue
文件内导入:
其中导入的css文件是在assets文件夹下建的css文件夹,再建一个base.css
文件,写入最基本的样式,再导入到App.vue
文件中
base.css
代码如下:
body{
margin:0;
padding:0;
}
App.vue样式代码如下:
<style>
/* 导入css文件 */
@import "./assets/css/base.css";
/* 实现水平分布 */
#tab-bar{
display:flex;
/* 添加背景颜色 */
background-color: #f6f6f6;
/* 将文字设置到页面底部 */
position:fixed;
left:0;
right: 0;
bottom: 0;
/* 界面和文字过渡部分添加阴影 */
box-shadow: 0 -1px 1px rgb(100,100,100,0.1);
}
/* 等分分布 给每个分类都设置一个类*/
.tab-bar-item{
flex:1;
/* 居中 */
text-align: center;
/* 设置高度 一般都设置为49*/
height: 49px;
}
</style>
最后效果:
3.封装成独立的组件
以上方法没有复用性,为了将整个模块可以成为插件直接使用,需要对每个部分进行封装(升级)。
首先分离出一个TabBar.vue
文件
图片和文字内容最后替换到slot的插槽里。
代码部分:
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
/* 实现水平分布 */
#tab-bar{
display:flex;
/* 添加背景颜色 */
background-color: #f6f6f6;
/* 将文字设置到页面底部 */
position:fixed;
left:0;
right: 0;
bottom: 0;
/* 界面和文字过渡部分添加阴影 */
box-shadow: 0 -1px 1px rgb(100,100,100,0.1);
}
</style>
文字和图片的内容再分离出一个文件TabBarItem.vue
,以下是代码部分:
这里有关于图片和文字的样式但是具体内容需要动态获取,所以再放一个插槽。需要动态的获取图片和文字,此时就要用到插槽slot
<template>
<div class="tab-bar-item">
<!-- 图片和文字不要写死 可以放一个插槽在这 -->
<slot name="item-icon"></slot>
<slot name="item-text"></slot>
<!-- <img src="../../assets/img/tabbar/home.svg" alt="">
<div>首页</div> -->
</div>
</template>
<script>
export default {
name:'TabBarItem'
}
</script>
<style scoped>
/* 等分分布 给每个分类都设置一个类*/
.tab-bar-item{
flex:1;
/* 居中 */
text-align: center;
/* 设置高度 一般都设置为49*/
height: 49px;
/* 调整文字大小 */
font-size: 14px;
}
/* 设置图片的大小 */
.tab-bar-item img {
height:24px;
width: 24px;
/* 图片距上面有一定空间 */
margin-top: 3px;
/* 调整图片和文字中间距离 */
vertical-align:middle;
}
</style>
先将具体的图片和文字放到App.vue
代码中:(注意对这两个子组件的导入和使用,并且图片和文字会排到一层,但我们需要上下展示,所以需要一个层级关系,将文字用div包裹一下)
<template>
<div id="app">
<!-- 3.使用 -->
<tab-bar>
<!-- 要往这个插槽里面填内容 有几个内容就要写几个item-->
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/cart.svg" alt="">
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
// 1.导入
import TabBar from "./components/tabbar/TabBar.vue"
import TabBarItem from "./components/tabbar/TabBarItem.vue"
export default {
name: 'App',
components:{
// 2.注册
TabBar,
TabBarItem
}
}
</script>
<style>
/* 导入css文件 */
@import "./assets/css/base.css";
</style>
目前结果:
4.效果切换
目的:实现处于活跃状态时,图片和文字都为红色,可以设置一个状态isActive
,为true时,是活跃状态。
相当于要传入两张图片在一个地方,设置其类,处于某一个状态就显示对应的样式。需要在原来一张图片的插槽上再插入一个插槽:<slot name="item-icon-active"></slot>
,在App.vue中加入相应的具体图片,例如:
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
//新插入
<img slot="item-icon-active" src="./assets/img/tabbar/home_active.svg" alt="">
<div slot="item-text">首页</div>
</tab-bar-item>
在TabBarItem.vue
中添加相应的方法:
<script>
export default {
name:'TabBarItem',
data(){
return{
isActive:true
}
}
}
</script>
TabBarItem.vue
设中置组件:
注意:1.绑定样式不要在插槽中修改,用一个div包裹起来,在div上设置属性 2.用 v-if 和 v-else 来选择其状态
具体代码如下:
<template>
<div class="tab-bar-item">
<!-- 图片和文字不要写死 可以放一个插槽在这 -->
<div v-if="!isActive">
<slot name="item-icon"></slot>
</div>
<div v-else>
<slot name="item-icon-active"></slot>
</div>
<!-- 动态改变文字颜色 因为插槽会被替换掉,因此将样式设置到div内-->
<div :class="{active:isActive}">
<slot name="item-text"></slot>
</div>
<!-- <img src="../../assets/img/tabbar/home.svg" alt="">
<div>首页</div> -->
</div>
</template>
5.路由跳转
实现点击下部导航栏出现相应的导航栏内容,路由跳转
5.1在src文件夹下新建一个文件夹views,在views文件夹下再新建四个对应的文件夹,再创建vue文件,如下图所示:
Home.vue
代码如下:
<template>
<div>
<h2>首页</h2>
</div>
</template>
<script>
export default {
name:"Home"
}
</script>
<style scoped>
</style>
5.2在router文件夹的index.js文件中导入这几个路由
// 导入每个路由
const Home = () => import('../views/home/Home')
const Category = () => import ('../views/category/Category')
const Cart = ()=> import('../views/cart/Cart')
const Profile = () => import('../views/profile/Profile')
//创建路由对象
const routes = [
{
path: '',
redirect:'/home'
},
{
path:'/home',
component: Home
},
{
path:'/category',
component: Category
},
{
path:'/cart',
component: Cart
},
{
path:'/profile',
component: Profile
}
]
此时,不同路由已经导入到index文件中
5.3监听点击事件
点击下部导航栏跳转到不同的路由界面。
在TabBarItem.vue
文件中,先监听点击事件,如下图红圈部分:
通过输入的路径获得此时需要跳转的路由,在TabBarItem.vue
事件触发:
(注意其中有一个报错,看网上资料在this.$router.replace(this.path).catch(err =>err)
加上 .catch这部分就不会报错)
<script>
export default {
name:'TabBarItem',
props:{
path: String
},
data(){
return{
isActive:false
}
},
methods:{
itemClick(){
this.$router.replace(this.path).catch(err =>err)
// console.log("123")
}
}
}
此时,在App.vue
文件中需要传入不同的路径:
下面代码的path='/home'
部分:
<tab-bar-item path="/home">
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/home_active.svg" alt="">
<div slot="item-text">首页</div>
</tab-bar-item>
现在就可以实现点击下列导航栏实现路由跳转。
6.封装字体颜色
字体颜色之前设置的固定值,要动态传入颜色,分活跃时和不活跃时的状态。
在TbaBarItem.vue
文件中,添加传入颜色的属性,
props:{
path: String,
activeColor:{
type: String,
default:'red'
}
},
并且通过三元运算符实现:处于活跃状态时,使用这个活跃的颜色:
activeStyle(){
return this.isActive? {color:this.activeColor} : {}
}
再绑定这个属性:
<div :style="activeStyle">
<slot name="item-text"></slot>
</div>
整体代码:
<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内-->
<div :style="activeStyle">
<slot name="item-text"></slot>
</div>
<!-- <img src="../../assets/img/tabbar/home.svg" alt="">
<div>首页</div> -->
</div>
</template>
<script>
export default {
name:'TabBarItem',
props:{
path: String,
activeColor:{
type: String,
default:'red'
}
},
computed:{
isActive(){
return this.$route.path.indexOf(this.path) !== -1
},
activeStyle(){
return this.isActive? {color:this.activeColor} : {}
}
},
data(){
return{
// isActive:false
}
},
methods:{
itemClick(){
this.$router.replace(this.path).catch(err =>err)
// console.log("123")
}
}
}
</script>
<style scoped>
/* 等分分布 给每个分类都设置一个类*/
.tab-bar-item{
flex:1;
/* 居中 */
text-align: center;
/* 设置高度 一般都设置为49*/
height: 49px;
/* 调整文字大小 */
font-size: 14px;
}
/* 设置图片的大小 */
.tab-bar-item img {
height:24px;
width: 24px;
/* 图片距上面有一定空间 */
margin-top: 3px;
/* 调整图片和文字中间距离 */
vertical-align:middle;
}
/* 文字处于活跃状态时为红色 */
/* .active{
color: red;
} */
</style>
7.App.vue组件抽离
之前传入图片和具体文字都是再App.vue的template中传入,此时需要把这部分再抽离出来。
需要注意每个部分要导入的组件,以及图片的路径也需要更改。