table of Contents
git:https://gitee.com/cxy-xupeng/vue-tab-bar.git
2. Initially make the following buttons
Three, click the button, route jump
4. Click to switch active state
git:https://gitee.com/cxy-xupeng/vue-tab-bar.git
One, create a project
Then we open the project and delete HelloWorld.vue and a part of App.vue. After deletion, it is as follows:
After deleting, enter
npm run dev
Enter the webpage, there is nothing on the page at this time, the preparation work is complete
2. Initially make the following buttons
Look at the catalog first:
Our TabBar.vue corresponds to a whole row, and TabBarItem.vue corresponds to each button.
Mainly uses the slot, which makes the subsequent reuse easier
TabBar.vue
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default{
name:'TabBar'
}
</script>
<style>
#tab-bar{
/* 水平分布*/
display: flex;
/* 背景色*/
background-color: #f6f6f6;
/* 位置*/
position: fixed;
left: 0;
right: 0;
bottom: 0;
/* 阴影*/
box-shadow: 0 -3px 1px rgba(100,100,100,0.2);
}
</style>
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{
name:'TabBarItem',
data(){
return{
isActive:true
}
},
}
</script>
<style>
.tab-bar-item{
/* 均等分布*/
flex:1;
/* 居中*/
text-align: center;
/* 高度*/
height: 49px;
/* 文字大小*/
font-size: 14px;
margin-top: 3px;
}
.tab-bar-item img{
width: 24px;
height: 24px;
margin-top: 3px;
/* 去掉图片下面的3个像素*/
vertical-align: middle;
margin-bottom: 2px;
}
</style>
View app
<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/shoppingmart.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/TabBar.vue'
import TabBarItem from './components/tabbar/TabBarItem.vue'
export default {
name: 'App',
components: {
TabBar,
TabBarItem
}
}
</script>
<style>
@import url("./assets/css/base.css");
</style>
base.css
body{
padding: 0;
margin: 0;
}
Regarding these pictures, we can enter Baidu: Alibaba Vector Icon Library .
Then enter: shopping cart, homepage, my, category. Find two sets of corresponding pictures and download them yourself
run:
enter
npm run dev
You can see the effect we gave at the beginning of this step
Three, click the button, route jump
We now want to realize that when each button is clicked, the page will also change:
1. Import routing:
npm install vue-router --save
2. Table of Contents
Where TabBar.vue remains unchanged
Cart.vue
<template>
<h2>购物车</h2>
</template>
<script>
</script>
<style>
</style>
Category.vue
<template>
<h2>分类</h2>
</template>
<script>
</script>
<style>
</style>
Home.vue
<template>
<h2>首页</h2>
</template>
<script>
</script>
<style>
</style>
Profile.vue
<template>
<h2>我的</h2>
</template>
<script>
</script>
<style>
</style>
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")
/* 1.安装插件 */
Vue.use(VueRouter)
/* 2.创建路由对象 */
const routes = [
{
path:'',
redirect:'/home'
},
{
path:'/home',
component:Home
},
{
path:'/category',
component:Category
},
{
path:'/cart',
component:Cart
},
{
path:'/profile',
component:Profile
}
]
const router = new VueRouter({
routes
})
/* 3.导出router */
export default router
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(App)
})
View app
<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/homeActive.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/categoryActive.svg" alt="" />
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/cart">
<img slot="item-icon" src="./assets/img/tabbar/shoppingmart.svg" alt="" />
<img slot="item-icon-active" src="./assets/img/tabbar/shoppingmartActive.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/profileActive.svg" alt="" />
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from './components/tabbar/TabBar.vue'
import TabBarItem from './components/tabbar/TabBarItem.vue'
export default {
name: 'App',
components: {
TabBar,
TabBarItem
}
}
</script>
<style>
@import url("./assets/css/base.css");
</style>
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 :class="{active:isActive}"><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default{
name:'TabBarItem',
props:{
path:String
},
data(){
return{
isActive:true
}
},
methods:{
itemClick(){
this.$router.replace(this.path).catch(err=>{})
}
}
}
</script>
<style>
.tab-bar-item{
/* 均等分布*/
flex:1;
/* 居中*/
text-align: center;
/* 高度*/
height: 49px;
/* 文字大小*/
font-size: 14px;
margin-top: 3px;
}
.tab-bar-item img{
width: 24px;
height: 24px;
margin-top: 3px;
/* 去掉图片下面的3个像素*/
vertical-align: middle;
margin-bottom: 2px;
}
</style>
4. Click to switch active state
Requirement: Which icon to click, which icon is bright, and the color of the word also changes accordingly. Of course, the color of the words should not be hard to write
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:{
path:String,
activeColor:{
type:String,
default:'red'
}
},
data(){
return{
}
},
computed:{
isActive(){
//判断路径是否为当前路径。找不到为-1,找到就不等于-1
return this.$route.path.indexOf(this.path) != -1
},
activeStyle(){
return this.isActive?{color:this.activeColor}:{}
}
},
methods:{
itemClick(){
this.$router.replace(this.path).catch(err=>{})
}
}
}
</script>
<style>
.tab-bar-item{
/* 均等分布*/
flex:1;
/* 居中*/
text-align: center;
/* 高度*/
height: 49px;
/* 文字大小*/
font-size: 14px;
margin-top: 3px;
}
.tab-bar-item img{
width: 24px;
height: 24px;
margin-top: 3px;
/* 去掉图片下面的3个像素*/
vertical-align: middle;
margin-bottom: 2px;
}
.active{
color: red;
}
</style>
View app
<template>
<div id="app">
<router-view></router-view>
<tab-bar>
<tab-bar-item path="/home" activeColor="blue">
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="" />
<img slot="item-icon-active" src="./assets/img/tabbar/homeActive.svg" alt="" />
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item path="/category" activeColor="red">
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="" />
<img slot="item-icon-active" src="./assets/img/tabbar/categoryActive.svg" alt="" />
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/cart" activeColor="green">
<img slot="item-icon" src="./assets/img/tabbar/shoppingmart.svg" alt="" />
<img slot="item-icon-active" src="./assets/img/tabbar/shoppingmartActive.svg" alt="" />
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item path="/profile" activeColor="pink">
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="" />
<img slot="item-icon-active" src="./assets/img/tabbar/profileActive.svg" alt="" />
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from './components/tabbar/TabBar.vue'
import TabBarItem from './components/tabbar/TabBarItem.vue'
export default {
name: 'App',
components: {
TabBar,
TabBarItem
}
}
</script>
<style>
@import url("./assets/css/base.css");
</style>
Five, streamline APP.Vue code
Do you think the APP.Vue code is very cumbersome, we need to streamline it
table of Contents:
MainTabBar.vue
<template>
<tab-bar>
<tab-bar-item path="/home" activeColor="blue">
<img slot="item-icon" src="../assets/img/tabbar/home.svg" alt="" />
<img slot="item-icon-active" src="../assets/img/tabbar/homeActive.svg" alt="" />
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item path="/category" activeColor="red">
<img slot="item-icon" src="../assets/img/tabbar/category.svg" alt="" />
<img slot="item-icon-active" src="../assets/img/tabbar/categoryActive.svg" alt="" />
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/cart" activeColor="green">
<img slot="item-icon" src="../assets/img/tabbar/shoppingmart.svg" alt="" />
<img slot="item-icon-active" src="../assets/img/tabbar/shoppingmartActive.svg" alt="" />
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item path="/profile" activeColor="pink">
<img slot="item-icon" src="../assets/img/tabbar/profile.svg" alt="" />
<img slot="item-icon-active" src="../assets/img/tabbar/profileActive.svg" alt="" />
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</template>
<script>
import TabBar from './tabbar/TabBar.vue'
import TabBarItem from './tabbar/TabBarItem.vue'
export default {
name: 'MainTabBar',
components: {
TabBar,
TabBarItem
}
}
</script>
<style>
</style>
View app
<template>
<div id="app">
<router-view></router-view>
<main-tab-bar></main-tab-bar>
</div>
</template>
<script>
import MainTabBar from './components/MainTabBar.vue'
export default {
name: 'App',
components: {
MainTabBar
}
}
</script>
<style>
@import url("./assets/css/base.css");
</style>
Six, file path reference
Some paths are very long and are easy to quote errors. We can give the path an alias:
We see that the @ in webpack.base.conf.js represents the src folder
(After modifying the configuration file, remember to restart the service)
Note: This writing method is only useful for import, if it is the src of the picture, it will not work.
If you want to use src, you need to add'~' in front
Seven, complete code
1. Table of Contents
2.webpack.base.conf.js
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
'assets':resolve('src/assets'),
'components':resolve('src/components'),
'views':resolve('src/views'),
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
3.base.css
body{
padding: 0;
margin: 0;
}
4.TabBar.vue
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default{
name:'TabBar'
}
</script>
<style>
#tab-bar{
/* 水平分布*/
display: flex;
/* 背景色*/
background-color: #f6f6f6;
/* 位置*/
position: fixed;
left: 0;
right: 0;
bottom: 0;
/* 阴影*/
box-shadow: 0 -3px 1px rgba(100,100,100,0.2);
}
</style>
5.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:{
path:String,
activeColor:{
type:String,
default:'red'
}
},
data(){
return{
}
},
computed:{
isActive(){
//判断路径是否为当前路径。找不到为-1,找到就不等于-1
return this.$route.path.indexOf(this.path) != -1
},
activeStyle(){
return this.isActive?{color:this.activeColor}:{}
}
},
methods:{
itemClick(){
this.$router.replace(this.path).catch(err=>{})
}
}
}
</script>
<style>
.tab-bar-item{
/* 均等分布*/
flex:1;
/* 居中*/
text-align: center;
/* 高度*/
height: 49px;
/* 文字大小*/
font-size: 14px;
margin-top: 3px;
}
.tab-bar-item img{
width: 24px;
height: 24px;
margin-top: 3px;
/* 去掉图片下面的3个像素*/
vertical-align: middle;
margin-bottom: 2px;
}
.active{
color: red;
}
</style>
6.MainTabBar.vue
<template>
<tab-bar>
<tab-bar-item path="/home" activeColor="blue">
<img slot="item-icon" src="~assets/img/tabbar/home.svg" alt="" />
<img slot="item-icon-active" src="~assets/img/tabbar/homeActive.svg" alt="" />
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item path="/category" activeColor="red">
<img slot="item-icon" src="~assets/img/tabbar/category.svg" alt="" />
<img slot="item-icon-active" src="~assets/img/tabbar/categoryActive.svg" alt="" />
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/cart" activeColor="green">
<img slot="item-icon" src="~assets/img/tabbar/shoppingmart.svg" alt="" />
<img slot="item-icon-active" src="~assets/img/tabbar/shoppingmartActive.svg" alt="" />
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item path="/profile" activeColor="pink">
<img slot="item-icon" src="~assets/img/tabbar/profile.svg" alt="" />
<img slot="item-icon-active" src="~assets/img/tabbar/profileActive.svg" alt="" />
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</template>
<script>
import TabBar from './tabbar/TabBar.vue'
import TabBarItem from './tabbar/TabBarItem.vue'
export default {
name: 'MainTabBar',
components: {
TabBar,
TabBarItem
}
}
</script>
<style>
</style>
7.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")
/* 1.安装插件 */
Vue.use(VueRouter)
/* 2.创建路由对象 */
const routes = [
{
path:'',
redirect:'/home'
},
{
path:'/home',
component:Home
},
{
path:'/category',
component:Category
},
{
path:'/cart',
component:Cart
},
{
path:'/profile',
component:Profile
}
]
const router = new VueRouter({
routes
})
/* 3.导出router */
export default router
8.View card
<template>
<h2>购物车</h2>
</template>
<script>
</script>
<style>
</style>
9.Category.vue
<template>
<h2>分类</h2>
</template>
<script>
</script>
<style>
</style>
10.Home.vue
<template>
<h2>首页</h2>
</template>
<script>
</script>
<style>
</style>
11.Profile.vue
<template>
<h2>我的</h2>
</template>
<script>
</script>
<style>
</style>
12.App.view
<template>
<div id="app">
<router-view></router-view>
<main-tab-bar></main-tab-bar>
</div>
</template>
<script>
import MainTabBar from './components/MainTabBar.vue'
export default {
name: 'App',
components: {
MainTabBar
}
}
</script>
<style>
@import url("./assets/css/base.css");
</style>
13.main.js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(App)
})