Vue從零開始封裝一個tabbar

         首先,底部菜單欄最外層是一個div,在div中整體上存在四個或五個小div,每個div中包含icon和text,如下圖

         對於每一個icon對象,它包含圖標以及文字,但十實際中我們肯定不會將img和text寫死,以及處於active狀態時text的顏色也不會寫死,以方便調用者傳入想要的參數,這樣纔算一個徹底的封裝。代碼如下:

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

<!--
    上方代碼設置三個插槽,爲什麼不是兩個呢,因爲還要包含當item處於活躍狀態時要顯示的image,所以是三個,使用v-if控制當非活躍時顯示默認icon插槽,活躍時顯示亮色icon插槽。因爲插槽是要被傳入其中的內容覆蓋的,所以傳入的內容可能會將我們slot中的一些屬性覆蓋掉,所以常常我們需要將slot包裹在div中,這樣就可以避免這個問題。
    icon下方文同理也放在div中,style綁定一個計算屬性,看下方代碼可以這個計算屬性當item處於活躍時會返回顏色屬性,當然這個屬性也是可以在調用tab-bar時傳入的,默認爲紅色。
-->

<script>
  export default {
    name:'TabBarItem',
    props:{
      path: String,  // 當前item對應的路由,由調用者指定
      activeColor:{  // 當前item的文字在活躍時的顏色,默認紅色,可由使用者指定
        type:String,
        default:"red"
      }
    },
    data() {
      return {
        // isActive:false,
      }
    },
    computed:{
      // 判斷當前item是否處於活躍狀態
      isActive(){
        return this.$route.path.indexOf(this.path)!==-1;
      },
      // 計算屬性,如果處於活躍狀態則設置style,否則去除style
      activeStyle(){
        return this.isActive? {color:this.activeColor}:{};
      }
    },
    methods:{
      itemClick(){
        if(this.$route.path!==this.path){
          this.$router.push(this.path);
          // this.isActive = true;
        } 
      }
    }
  }
</script>

<style scoped>
<!--一些默認樣式-->
  .tab-bar-item {
    flex: 1;
    text-align: center;
    height: 49px;
    font-size: 10px;
  }
  .tab-bar-item img {
    margin-top: 4px;
    width: 22px;
    height: 22px;
    vertical-align: middle;
    margin-bottom: 2px;
  }
</style>

封裝完每一個tabbaritem後,接下來是整體的tabbar,試想,我們肯定還是放入一個插槽代碼如下: 

<template>
  <div id="tab-bar">
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "TabBar"
};
</script>

<style scoped>
#tab-bar {
  display: flex;
  background-color: #f6f6f6;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  box-shadow: 0px -2px 1px rgba(100, 100, 100, 0.1);
}
 
</style>

 tabbar預留的插槽則用於放入每一個item,我們在這裏也是不能寫死的,因爲控件開發者並不知需要放入多少個item。

使用者在使用我們封裝的控件時,則可以如下代碼,放入內容:

<template>
  <tab-bar>
      <tab-bar-item path="/home" activeColor="deepPink">
        <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" activeColor="deepPink">
        <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="/cart" activeColor="deepPink">
        <img slot="item-icon" src="~assets/img/tabbar/cart.svg" alt="">
        <img slot="item-icon-active" src="~assets/img/tabbar/cart_active.svg" alt="">
        <div slot="item-text">購物車</div>
      </tab-bar-item>
      <tab-bar-item path="/profile" activeColor="deepPink">
        <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>
  
</template>

<script>
  import TabBar from "components/tabbar/TabBar";
  import TabBarItem from "components/tabbar/TabBarItem";
  export default {
    name:'MainTabBar',
    components:{
      TabBar,
      TabBarItem
    }
  }
</script>

<style scoped>
</style>

到此結束。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章