效果图
vue init webpack TabBar
目录结构
结构搭建
APP.vue
<template>
<div id="app">
<div class="tabbar">
<div class="tab-bar-item">
<img src="../assets/img/tabbar/home.svg" alt="">
首页</div>
<div class="tab-bar-item">
<img src="../assets/img/tabbar/home.svg" alt="">
分类</div>
<div class="tab-bar-item">
<img src="../assets/img/tabbar/home.svg" alt="">
商城</div>
<div class="tab-bar-item">
<img src="../assets/img/tabbar/home.svg" alt="">
我的</div>
</div>
</div>
</template>
<script>
import TabBar from './components/TabBar.vue'
export default {
name: 'App',
components:{
TabBar
}
}
</script>
<style>
//css引入方式
@import url('./assets/css/base.css');
.tabbar{
display: flex;
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 49px;
background-color: #f6f6f6;
line-height: 49px;
font-size: 18px;
box-shadow: 0 -2px rgba(0,0,0,.1);
}
.tab-bar-item{
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
}
</style>
此时效果
文件抽离成组件
都放在APP.vue里过于繁琐
新建TabBar.vue
<template>
<div class="tabbar">
<div class="tab-bar-item">
<img src="../assets/img/tabbar/home.svg" alt="">
首页</div>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt="">分类</div>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt="">商城</div>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt="">我的</div>
</div>
</template>
<script>
export default {
}
</script>
<style>
.tabbar{
display: flex;
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 49px;
background-color: #f6f6f6;
line-height: 49px;
font-size: 18px;
box-shadow: 0 -2px rgba(0,0,0,.1);
}
.tab-bar-item{
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
}
</style>
此时要在APP.vue中导入
<template>
<div id="app">
<!--使用组件-->
<tab-bar></tab-bar>
</div>
</template>
<script>
//导入组件
import TabBar from './components/TabBar.vue'
export default {
name: 'App',
//注册组件
components:{
TabBar
}
}
</script>
<style>
@import url('./assets/css/base.css');
</style>
但是此时TarBar又过于繁琐 它应该只管理TarBar的东西 无需管理tar-bar-item的东西
所以只需要在TarBar中定义一个插槽 tar-bar-item的东西放到APP.vue中进行渲染 如下:
TabBar.vue
<template>
<div class="tabbar">
<slot></slot>
</div>
</template>
<script>
export default {
}
</script>
<style>
.tabbar{
display: flex;
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 49px;
background-color: #f6f6f6;
line-height: 49px;
font-size: 18px;
box-shadow: 0 -2px rgba(0,0,0,.1);
}
</style>
App.vue
<template>
<div id="app">
<tab-bar>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt="">首页</div>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt="">分类</div>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt="">商城</div>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt="">我的</div>
</tab-bar>
</div>
</template>
<script>
import TabBar from './components/TabBar.vue'
export default {
name: 'App',
components:{
TabBar
}
}
</script>
<style>
@import url('./assets/css/base.css');
.tab-bar-item{
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
}
</style>
但是很明显,此时APP.vue又过于复杂 所以我们还需要抽离成组件
新建TabBarItem组件:
//tab-bar-item的东西抽离到这里
<template>
<div class="tab-bar-item"><img src="../assets/img/tabbar/home.svg" alt=""> 首页</div>
</template>
<script>
export default {
}
</script>
<style>
.tab-bar-item{
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
}
</style>
App.vue
<template>
<div id="app">
<tab-bar>
<tab-bar-item></tab-bar-item>
<tab-bar-item></tab-bar-item>
<tab-bar-item></tab-bar-item>
<tab-bar-item></tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from './components/TabBar.vue'
import TabBarItem from './components/TabBarItem.vue'
export default {
name: 'App',
components:{
TabBar,
TabBarItem
}
}
</script>
<style>
@import url('./assets/css/base.css');
</style>
此时效果
但是此时TabBarItem中的内容是写死的 无法改变 而且展示的都是一样的东西 所以我们需要使用插槽
TabBarItem.vue
<template>
<div class="tar-bar-item">
<!-- 图片插槽 -->
<slot name="item-icon"></slot>
<!-- 文字插槽 -->
<slot name="item-text"></slot>
</div>
</template>
<script>
export default {
}
</script>
<style>
.tab-bar-item{
flex: 1;
text-align: center;
}
.tab-bar-item img{
width: 24px;
height: 24px;
}
</style>
此时就可以在APP.vue中定义不同的内容
<template>
<div id="app">
<tab-bar>
<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/shopcart.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>
import TabBar from './components/TabBar.vue'
import TabBarItem from './components/TabBarItem.vue'
export default {
name: 'App',
components:{
TabBar,
TabBarItem
}
}
</script>
<style>
@import url('./assets/css/base.css');
</style>
此时效果
到此 TabBar就已经封装好了 以后要使用就可以直接在APP.vue中定义不同内容了
但是此时只有一张图片 点击时无法更换图片
所以需要在定义一个插槽 并添加图片
TabBarItem.vue
<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 :class="{active:isActive}"><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default {
data() {
return{
isActive:true
}
}
}
</script>
<style>
.tab-bar-item{
flex: 1;
text-align: center;
margin-top: 3px;
margin-bottom: 2px;
font-size: 14px;
vertical-align: middle;
}
.tab-bar-item img{
width: 24px;
height: 24px;
}
.active{
color: red;
}
</style>
App.vue
<template>
<div id="app">
<tab-bar>
<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>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/category_active.svg" alt="">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/shopcart.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/shopcart_active.svg" alt="">
<div slot="item-text">商城</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/profile_active.svg" alt="">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from './components/TabBar.vue'
import TabBarItem from './components/TabBarItem.vue'
export default {
name: 'App',
components:{
TabBar,
TabBarItem
}
}
</script>
<style>
@import url('./assets/css/base.css');
</style>
插槽外面为啥加上div标签
如果不加 APP.vue中的内容会覆盖插槽 导致属性失效 加上div 覆盖插槽 也不会影响div中的属性
此时效果
现在进行路由配置
新建目录及文件
配置路由
import Vue from 'vue'
import Router from 'vue-router'
const Home = () =>
import ('../views/Home/Home')
const Category = () =>
import ('../views/Category/Category')
const Shopcart = () =>
import ('../views/Shuocart/Shopcart')
const Profile = () =>
import ('../views/Profile/Profile')
Vue.use(Router)
export default new Router({
routes: [{
path: '',
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/category',
component: Category
},
{
path: '/shopcart',
component: Shopcart
},
{
path: '/profile',
component: Profile
},
],
mode: 'history'
})
配置 点击事件进行页面跳转
<template>
<div class="tab-bar-item" @click="Btnclick">
<!-- 图片插槽 -->
<div v-if="!isActive"><slot name="item-icon"></slot></div>
<!-- 点击时图片插槽 -->
<div v-else><slot name="item-icon-active"></slot></div>
<!-- 文字插槽 -->
<div :class="{active:isActive}"><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default {
//点击时 传过来的路径不能写死 所以需要props将路径传过来 路径在App.vue中定义
props:{
path:String
},
data() {
return{
isActive:true,
}
},
methods:{
Btnclick() {
//获取路径
this.$router.push(this.path)
}
}
}
</script>
<style>
.tab-bar-item{
flex: 1;
text-align: center;
margin-top: 3px;
margin-bottom: 2px;
font-size: 14px;
vertical-align: middle;
}
.tab-bar-item img{
width: 24px;
height: 24px;
}
.active{
color: red;
}
</style>
App.vue中
<!-- 这里的path:'/home'等就是通过props传过去的路径 -->
<template>
<div id="app">
<router-view></router-view>
<tab-bar>
<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>
<tab-bar-item path="/category">
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/category_active.svg" alt="">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/shopcart">
<img slot="item-icon" src="./assets/img/tabbar/shopcart.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/shopcart_active.svg" alt="">
<div slot="item-text">商城</div>
</tab-bar-item>
<tab-bar-item path="/profile">
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/profile_active.svg" alt="">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
到此 点击不同tabbaritem就可以进行页面跳转
此时还有一个问题 当我不点击时 active图片还是会显示
所以要进行修改
data() {
return{
// isActive:true,
}
},
computed:{
isActive() {
return this.$route.path.indexOf(this.path) !== -1
}
},
isActive不要写死
return this.$route.path.indexOf(this.path) !== -1
this.$route.path 拿到当前活跃的路由 也就是点击的路由
判断它和this.path相不相等 相等返回1
在对应
<div v-if="!isActive"><slot name="item-icon"></slot></div>
<div v-else><slot name="item-icon-active"></slot></div>
就可以进行点击时图片切换
此时还有一个问题 文字颜色我们设置了红色 如果修改就要进到封装好的 组件中修改
所以进行以下修改
props:{
path:String,
activeColor:{
type:String,
default:'red'
}
},
data() {
return{
// isActive:true,
}
},
computed:{
isActive() {
return this.$route.path.indexOf(this.path) !== -1
},
activeStyle() {
//判断isActive是否为true 为true就activeColor false就为空
return this.isActive ? {color:this.activeColor} : {}
}
},
methods:{
Btnclick() {
this.$router.push(this.path)
}
}
//动态绑定style
<div :style="activeStyle"><slot name="item-text"></slot></div>
//这里添加要修改的颜色
<tab-bar-item path="/home" activeColor= "blue">
完
总结:
v-if v-else的使用
计算属性的使用
组件化抽离的思想
插槽的使用
路由的配置
props的使用