49.vue example (1): tabbar

table of Contents

git:https://gitee.com/cxy-xupeng/vue-tab-bar.git

One, create a project

2. Initially make the following buttons

Three, click the button, route jump

4. Click to switch active state

Five, streamline APP.Vue code

Six, file path reference

Seven, complete code


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)
})

 

Guess you like

Origin blog.csdn.net/qq_40594696/article/details/110921318