基于CLI学完后所做的第一个较大的vue案例
0.思路
- 在App.vue中搭建大致的底部栏样式
 
- 拆解底部栏(大框+切换选项)
 
- 创建路由
 
- 实现动态切换路由(v-on)
 
- 实现动态切换样式(v-bind、props、computed、$route、$router)
 
- 整合底部栏并抽离出一个完整的底部栏组件,并在app.vue导入该完整的底部栏组件
 
1.结构搭建
首先,就是在app.vue里面将大致结构搭建出来
template代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | <div class="tab-bar">   <div class="tab-item">     <img src="../../assets/image/tabbar/home.svg" alt="" slot="image">     <img src="../../assets/image/tabbar/home_active.svg" alt="" slot="img-active">     <div slot="item">首页</div>   </div>   <div class="tab-item">     <img src="../../assets/image/tabbar/home.svg" alt="" slot="image">     <img src="../../assets/image/tabbar/home_active.svg" alt="" slot="img-active">     <div slot="item">首页</div>   </div>   <div class="tab-item">     <img src="../../assets/image/tabbar/home.svg" alt="" slot="image">     <img src="../../assets/image/tabbar/home_active.svg" alt="" slot="img-active">     <div slot="item">首页</div>   </div>   <div class="tab-item">     <img src="../../assets/image/tabbar/home.svg" alt="" slot="image">     <img src="../../assets/image/tabbar/home_active.svg" alt="" slot="img-active">     <div slot="item">首页</div>   </div> </div>
   | 
 
style代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | <style> .tab-bar {   display: flex;   position: fixed;   bottom: 0;   left: 0;   right: 0;   background-color: #f6f6f6; }
  .tab-item {   flex: 1;   height: 49px;   text-align: center; }
  .tab-item img {   width: 24px;   height: 24px;   margin-top: 3px;   vertical-align: middle;   margin-bottom: 2px; } </style>
   | 
 
2.根据代码进行模块拆解
在components文件夹下新建一个Tabbar.vue文件
将外部框,也就是包裹四个选项按钮的框进行抽离
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   | <template>   <div class="tab-bar">     <tab-bar-item>       <img slot="img" src="../../assets/image/tabbar/home.svg" alt="">       <div slot="item">首页</div>     </tab-bar-item>          <tab-bar-item>       <img slot="img" src="../../assets/image/tabbar/category.svg" alt="">       <div slot="item">分类</div>             </tab-bar-item>          <tab-bar-item>       <img slot="img" src="../../assets/image/tabbar/shopcart.svg" alt="">       <div slot="item">购物车</div>              </tab-bar-item>          <tab-bar-item>       <img slot="img" src="../../assets/image/tabbar/profile.svg" alt="">       <div slot="item">我的</div>              </tab-bar-item>     </div> </template>
  <script>   import TabbarItem from "./TabbarItem.vue"   export default {     name: "Tabbar",     components: {       TabbarItem     }   } </script>
  <style scoped>   .tabbar {     display: flex;     position: fixed;     bottom: 0;     left: 0;     right: 0;     background-color: #f6f6f6;   } </style>
   | 
 
在该文件夹下再新建TabbarItem.vue文件并进行每个子选项(按钮)的代码抽离
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | <template>   <div class="tab-item">     <slot name="image"></slot>     <slot name="item"></slot>       </div> </template>
  <script>   export default {     name: "TabbarItem"   } </script>
  <style scoped>   .tab-item {     flex: 1;     height: 49px;     text-align: center;   }   .tab-item img {     width: 24px;     height: 24px;     margin-top: 3px;     vertical-align: middle;     margin-bottom: 2px;   } </style>
   | 
 
3.创建路由,构建相关路由页面
路由代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
   |  import Vue from 'vue' import VueRouter from 'vue-router'
  const Home = () => import('../views/Home/Home.vue') const Category = () => import('../views/Category/Category.vue') const Profile = () => import('../views/Profile/Proile.vue') const Shopcart = () => import('../views/Shopcart/Shopcart.vue')
 
 
  Vue.use(VueRouter)
 
  const routes = [   {     path: '',          redirect: '/home',   },     {     path: '/home',     name: 'home',     component: Home   },   {     path: '/category',     name: 'category',     component: Category   },   {     path: '/shopcart',     name: 'shopcart',     component: Shopcart   },   {     path: '/profile',     name: 'profile',     component: Profile   }]
 
  const router = new VueRouter({   routes,   mode: 'history' 
  })
 
  export default router
 
  | 
 
相关路由页面目录

4.动态切换路由
跳回到TabbarItem.vue文件,为其动态绑定一个点击事件change
1 2 3
   | <div class="tab-item" @click="change">   </div>
   | 
 
实现具体的路由跳转操作
1 2 3 4 5 6 7 8 9 10
   | <script>   export default {     name: "TabbarItem",     methods: {       change() {         this.$router.push(this.path)       }     }   } </script>
   | 
 
到这一步,你会发现是不能完成路由跳转的,因为我们需要动态获取到用户点击的是哪个按钮,我们需要动态的获取父级的按钮选项中要跳转的页面,所以我们到它的父级页面去定义一个path属性,同时赋上各自的路由地址
Tabbar.vue代码(path=”地址”)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | <template>   <div class="tab-bar">     <tab-bar-item path="/home" >       <img slot="img" src="../../assets/image/tabbar/home.svg" alt="">       <img slot="img-active" src="../../assets/image/tabbar/home_active.svg" alt="">       <div slot="item">首页</div>     </tab-bar-item>          <tab-bar-item path="/category">       <img slot="img" src="../../assets/image/tabbar/category.svg" alt="">       <img slot="img-active" src="../../assets/image/tabbar/category_active.svg" alt="">       <div slot="item">分类</div>             </tab-bar-item>          <tab-bar-item path="/shopcart">       <img slot="img" src="../../assets/image/tabbar/shopcart.svg" alt="">       <img slot="img-active" src="../../assets/image/tabbar/shopcart_active.svg" alt="">       <div slot="item">购物车</div>              </tab-bar-item>          <tab-bar-item path="/profile">       <img slot="img" src="../../assets/image/tabbar/profile.svg" alt="">       <img slot="img-active" src="../../assets/image/tabbar/profile_active.svg" alt="">       <div slot="item">我的</div>              </tab-bar-item>     </div> </template>
   | 
 
TabbarItem定义props属性去接收这些变量
1 2 3 4 5 6 7 8 9 10 11 12 13
   | <script>   export default {     name: 'TabBarItem',     props:{       path: String,     },     methods: {       change() {         this.$router.push(this.path)       }     }   } </script>
   | 
 
5.切换选项样式改变
接着,为了实现点击哪个选项,哪个选项的图片以及字体颜色就会相应的改变,我们需要给TabbarItem一个判断语句,用来判断该组件对应的路由当前是否处于活跃状态,首先为图片定义if-else语句,对其进行判断,若活跃,则显示有颜色的图片,同时,定义一个计算属性-isActive,进行语句判断,若当前活跃的页面就是该组件路由,则显示活跃的图片样式—核心代码(  this.$route.path.indexOf(this.path) !== -1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
   | <template>   <div class="tab-item" @click="change">     <div v-if="!isActive">       <slot name="img"></slot>     </div>     <div v-else>       <slot name="img-active"></slot>          </div>       <slot name='item'></slot>   </div> </template>
  <script>   export default {     name: 'TabBarItem',     props:{       path: String,     },     methods: {       change() {         this.$router.push(this.path)       }     }     computed: {       isActive() {         return this.$route.path.indexOf(this.path) !== -1       }     }   } </script>
  <style scoped>   .tab-item {   flex: 1;   height: 49px;   text-align: center; } .tab-item img {     width: 24px;     height: 24px;     margin-top: 3px;     /* 去除图片底部内容 */     vertical-align: middle;     margin-bottom: 2px; } /* .isred {   color: red } */ </style>
   | 
 
然后,动态绑定style,同样使用isActive计算属性进行判断
为字体动态绑定样式
1 2 3
   | <div :style="activeStyle">   <slot name='item'></slot> </div>
   | 
 
方法具体实现
1 2 3 4 5
   | computed: {   activeStyle() {     return this.isActive ? {color: red} :{}   } }
  | 
 
如果想为其自定义颜色,可以为其定义一个可以动态获取它父组件的属性
1 2 3 4 5 6 7 8
   | props:{   path: String,      activeColor: {     type: String,     default: 'red'   } }
  | 
 
然后你就可以自定义你想要的颜色啦
在其父组件下自定义颜色
1 2 3 4 5
   | <tab-bar-item path="/home" activeColor="blue" >   <img slot="img" src="../../assets/image/tabbar/home.svg" alt="">   <img slot="img-active" src="../../assets/image/tabbar/home_active.svg" alt="">   <div slot="item">首页</div> </tab-bar-item>  
   | 
 
6.组件抽离,插槽安排
然后就是将Tabbar.vue进行抽离,定义一个插槽供插入的选项按钮,然后再新建一个MainTabbar文件用来组装这些组件,最后再在App.vue中引用该组件
最后的代码
Tabbar.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | <template>     <div class="tab-bar">       <slot></slot>     </div> </template> <script> export default {   name: 'TarBar' } </script> <style scoped> .tab-bar {   display: flex;
    position: fixed;   bottom: 0;   left: 0;   right: 0;   background-color: #C7C7C7;   box-shadow: 0, -1px, 1px, rgba(216, 214, 214, 0.1) }
  </style>
   | 
 
TabbarItem.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
   | <template>   <div class="tab-item" @click="change">     <div v-if="!isActive">       <slot name="img"></slot>     </div>     <div v-else>       <slot name="img-active"></slot>          </div>     <div :style="activeStyle">       <slot name='item'></slot>     </div>   </div> </template>
  <script>   export default {     name: 'TabBarItem',     props:{       path: String,       activeColor: {         type: String,         default: 'red'       }     },     methods: {       change() {         this.$router.push(this.path)       }     },     data() {       return {       }     },     computed: {       isActive() {         return this.$route.path.indexOf(this.path) !== -1       },       activeStyle() {         return this.isActive ? {color: this.activeColor} :{}       }     }   } </script>
  <style scoped>   .tab-item {   flex: 1;   height: 49px;   text-align: center; } .tab-item img {     width: 24px;     height: 24px;     margin-top: 3px;     /* 去除图片底部内容 */     vertical-align: middle;     margin-bottom: 2px; } </style>
   | 
 
MainTabbar.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
   | <template>   <div>     <tab-bar>       <tab-bar-item path="/home" >         <img slot="img" src="../../assets/image/tabbar/home.svg" alt="">         <img slot="img-active" src="../../assets/image/tabbar/home_active.svg" alt="">         <div slot="item">首页</div>       </tab-bar-item>            <tab-bar-item path="/category">         <img slot="img" src="../../assets/image/tabbar/category.svg" alt="">         <img slot="img-active" src="../../assets/image/tabbar/category_active.svg" alt="">         <div slot="item">分类</div>               </tab-bar-item>            <tab-bar-item path="/shopcart">         <img slot="img" src="../../assets/image/tabbar/shopcart.svg" alt="">         <img slot="img-active" src="../../assets/image/tabbar/shopcart_active.svg" alt="">         <div slot="item">购物车</div>                </tab-bar-item>            <tab-bar-item path="/profile">         <img slot="img" src="../../assets/image/tabbar/profile.svg" alt="">         <img slot="img-active" src="../../assets/image/tabbar/profile_active.svg" alt="">         <div slot="item">我的</div>                </tab-bar-item>          </tab-bar>   </div> </template>
  <script>   import TabBar from "../tabbar/TabBar.vue"   import TabBarItem from "../tabbar/TabBarItem.vue"   export default {     name: 'MainTabBar',     components: {       TabBar,       TabBarItem     }   } </script>
  <style scoped>   </style>
   | 
 
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | <template>   <div id="app">     <router-view></router-view>     <main-tab-bar></main-tab-bar>   </div> </template>
  <script>   import MainTabBar from "./components/maintabbar/MainTabBar.vue"   export default {     name: 'App',     components: {       MainTabBar     }   } </script>
  <style>   /* css样式代码引用 */   @import "./assets/css/base.css"; </style>
   |