Vue CLI 2 腳手架 TabBar 組件封裝

作者:辰風沐陽 閱讀:1542 發(fā)布時間:2022-01-12 上次更新:2022-01-14

1. 前言


本文記錄在 vue cli 2 中封裝 tabbar 組件詳細步驟,主要是為了感受 vue 的組件封裝思想,也是前面學習 vue 基礎的練習案例

2. 清理腳手架


刪除圖片: src/assets/logo.png

刪除 HelloWorld 組件: src/components/HelloWorld.vue

清理 HelloWorld 組件: src/router/index.js (HelloWorld 組件路由配置)

清理 APP 組件: src/App.vue, 去除樣式代碼和模板內(nèi)容,清理后內(nèi)容如下:

  1. <template>
  2. <div id="app"></div>
  3. </template>
  4. <script>
  5. export default {
  6. name: "App",
  7. };
  8. </script>
  9. <style>
  10. </style>

3. 搭建 tabbar 基本布局


APP 組件

  1. <template>
  2. <div id="app">
  3. <div id="tab-bar">
  4. <div>首頁</div>
  5. <div>分類</div>
  6. <div>購物車</div>
  7. <div>我的</div>
  8. </div>
  9. </div>
  10. </template>

tabbar 圖片存放目錄: src/assets/img/tabbar

基礎樣式文件: src/assets/css/base.css

  1. body {
  2. margin: 0;
  3. padding: 0;
  4. }

在 APP 組件的 style 標簽中導入基礎樣式文件

  1. <style>
  2. @import "./assets/css/base.css";
  3. </style>

4. 書寫 tabbar 基本樣式


補充: tabbar 高度一般都是 49px,文字大小 14px

模板內(nèi)容

  1. <template>
  2. <div id="app">
  3. <div id="tab-bar">
  4. <div class="tab-bar-item">首頁</div>
  5. <div class="tab-bar-item">分類</div>
  6. <div class="tab-bar-item">購物車</div>
  7. <div class="tab-bar-item">我的</div>
  8. </div>
  9. </div>
  10. </template>

樣式代碼

  1. @import "./assets/css/base.css";
  2. #tab-bar {
  3. display: flex;
  4. position: fixed;
  5. left: 0;
  6. right: 0;
  7. bottom: 0;
  8. background-color: #f6f6f6;
  9. box-shadow: 0 -1px 1px rgba(100, 100, 100, 0.1);
  10. }
  11. .tab-bar-item {
  12. flex: 1;
  13. height: 49px;
  14. text-align: center;
  15. font-size: 14px;
  16. }

效果如下圖所示

5. TabBar 組件封裝


創(chuàng)建 TabBar 組件: src/components/tabbar/TabBar.vue

將 APP.vue 中的 tabbar 代碼抽離到 TabBar 組件中,TabBar 組件內(nèi)容:

  1. <template>
  2. <div id="tab-bar">
  3. <div class="tab-bar-item">首頁</div>
  4. <div class="tab-bar-item">分類</div>
  5. <div class="tab-bar-item">購物車</div>
  6. <div class="tab-bar-item">我的</div>
  7. </div>
  8. </template>
  9. <script>
  10. export default {
  11. name: "TabBar",
  12. };
  13. </script>
  14. <style scoped>
  15. #tab-bar {
  16. display: flex;
  17. position: fixed;
  18. left: 0;
  19. right: 0;
  20. bottom: 0;
  21. background-color: #f6f6f6;
  22. box-shadow: 0 -1px 1px rgba(100, 100, 100, 0.1);
  23. }
  24. .tab-bar-item {
  25. flex: 1;
  26. height: 49px;
  27. text-align: center;
  28. font-size: 14px;
  29. }
  30. </style>

調(diào)整 TabBar 組件

  1. <div id="tab-bar">
  2. <div class="tab-bar-item">
  3. <img src="@/assets/img/tabbar/home.png" />
  4. <div>首頁</div>
  5. </div>
  6. <div class="tab-bar-item">
  7. <img src="@/assets/img/tabbar/category.png" />
  8. <div>分類</div>
  9. </div>
  10. <div class="tab-bar-item">
  11. <img src="@/assets/img/tabbar/cart.png" />
  12. <div>購物車</div>
  13. </div>
  14. <div class="tab-bar-item">
  15. <img src="@/assets/img/tabbar/profile.png" />
  16. <div>我的</div>
  17. </div>
  18. </div>

增加樣式代碼 (tabbar 圖片大小一般是 24px)

  1. .tab-bar-item img {
  2. width: 24px;
  3. height: 24px;
  4. margin-top: 3px;
  5. vertical-align: middle;
  6. margin-bottom: 2px;
  7. }

當前效果

6. TabBarItem 組件封裝


此時組件容器 (#tab-bar) 和子項 (.tab-bar-item) 都在 TabBar 組件中,而 TabBar 應該只處理組件容器中的邏輯和樣式,子項應被抽離出去

所以,我們可以在 TabBar 組件中定義一個插槽, 并將子項 (.tab-bar-item) 樣式先抽離到 APP 組件中

抽離后 TabBar 組件:

抽離后 APP 組件:

通過上圖可發(fā)現(xiàn) APP 組件就復雜了,所以需要再創(chuàng)建一個 TabBarItem 組件

然后在 APP 組件中導入 TabBarItem 組件,如下圖所示:

現(xiàn)在 TabBarItem 組件是抽離出來了,但組件內(nèi)容還是死的,需要在 TabBarItem 組件中也定義插槽

  1. <template>
  2. <div class="tab-bar-item">
  3. <slot name="item-icon"></slot>
  4. <slot name="item-text"></slot>
  5. </div>
  6. </template>

然后 APP 組件就可以像下面這樣寫了

  1. <tab-bar-item>
  2. <img slot="item-icon" src="@/assets/img/tabbar/home.png" />
  3. <div slot="item-text">首頁</div>
  4. </tab-bar-item>

7. 給 TabBarItem 組件傳入選中時的圖片


當前組件中只有一個傳圖片的插槽,需要在添加一個傳菜單選中時圖片的插槽 (item-icon-active)

  1. <template>
  2. <div class="tab-bar-item">
  3. <slot name="item-icon"></slot>
  4. <slot name="item-icon-active"></slot>
  5. <slot name="item-text"></slot>
  6. </div>
  7. </template>

APP 組件

  1. <tab-bar-item>
  2. <img slot="item-icon" src="@/assets/img/tabbar/home.png" />
  3. <img slot="item-icon-active" src="@/assets/img/tabbar/home-active.png"/>
  4. <div slot="item-text">首頁</div>
  5. </tab-bar-item>

當前效果

此時我們需要添加個 isActive 數(shù)據(jù),代表菜單選中狀態(tài), 調(diào)整 TabBarItem 組件

  1. <template>
  2. <div class="tab-bar-item">
  3. <div v-if="!isActive">
  4. <slot name="item-icon"></slot>
  5. </div>
  6. <div v-else>
  7. <slot name="item-icon-active"></slot>
  8. </div>
  9. <div :class="{ active: isActive }">
  10. <slot name="item-text"></slot>
  11. </div>
  12. </div>
  13. </template>
  1. data() {
  2. return {
  3. isActive: false,
  4. };
  5. },
  1. .active {
  2. color: red;
  3. }

8. TabBarItem 組件和路由結合效果


創(chuàng)建底部菜單對應的組件: 首頁、分類、購物車、我的

  1. <template>
  2. <h2>首頁</h2>
  3. </template>
  4. <script>
  5. export default {
  6. name: "Home",
  7. };
  8. </script>
  9. <style scoped>
  10. </style>

添加路由映射配置: src/router/index.js

  1. const routes = [
  2. {
  3. path: "/home",
  4. component: () => import('@/views/home/Home')
  5. },
  6. {
  7. path: "/category",
  8. component: () => import('@/views/category/Category')
  9. },
  10. {
  11. path: "/cart",
  12. component: () => import('@/views/cart/Cart')
  13. },
  14. {
  15. path: "/profile",
  16. component: () => import('@/views/profile/Profile')
  17. },
  18. ]

TabBarItem 組件 props 屬性定義個 path 用于接收菜單路由, 并且給菜單容器綁定一個點擊事件

  1. <div class="tab-bar-item" @click="itemClick"></div>
  1. export default {
  2. name: "TabBarItem",
  3. props: {
  4. path: String,
  5. },
  6. data() {
  7. return {
  8. // isActive: false,
  9. };
  10. },
  11. computed: {
  12. isActive() {
  13. return this.$route.path.indexOf(this.path) !== -1;
  14. },
  15. },
  16. methods: {
  17. itemClick() {
  18. if (this.path !== this.$route.path) {
  19. // 路由跳轉
  20. this.$router.push(this.path);
  21. }
  22. },
  23. },
  24. };

調(diào)整APP 組件,將菜單路由用 path 屬性傳給子組件,并且 router-view 組件將路由組件內(nèi)容渲染出來

  1. <tab-bar>
  2. <tab-bar-item path="/home"></tab-bar-item>
  3. </tab-bar>
  4. <router-view></router-view>

9. TabBarItem 組件的顏色動態(tài)控制


TabBarItem 組件 props 中添加 activeColor 屬性用于接收菜單選中時的顏色,并且默認值為 red;添加計算屬性 activeStyle

  1. props: {
  2. activeColor: {
  3. type: String,
  4. default: "red",
  5. }
  6. },
  7. computed: {
  8. activeStyle() {
  9. return this.isActive ? { color: this.activeColor } : {};
  10. },
  11. },

  1. <div :class="{active: isActive}">
  2. <slot name="item-text"></slot>
  3. </div>

改為

  1. <div :style="activeStyle">
  2. <slot name="item-text"></slot>
  3. </div>

APP 組件則可以通過 activeColor 屬性控制菜單選中時的顏色,省略時默認為 red

  1. <tab-bar-item path="/home" activeColor="green"></tab-bar-item>

標簽: vue