I will share with you the packaging of Tabbar components using the front end framework VUEJs – forgive me for writing this article for the first time.

1. Why implement tabbar component encapsulation in the first place?

This is because most of the mobile programs adopt tabber components, which leads to the high frequency of use of Tabber. For convenience, the tabber component is encapsulated, which greatly solves the time. Every time you need to use tabbar to write a project, you can directly import it, and you do not need to spend time to repeat the same code. Cost savings.

2. Prelude preparation — slot

1. To encapsulate TabBar components, I mainly use slots, so before starting, I will briefly introduce slots

2. Before you learn about slots, understand a concept: compile scope

  • The official rule is that everything in a parent component template is compiled in the parent scope. Everything in a child component is compiled in the child scope.

  • In other words: the parent component replaces the label of the slot, but the content is provided by the child component.

3. Component slot

  • Slots for components are designed to make the components we encapsulate more extensible.

  • Let the consumer decide what to display inside the component.

  • Once we have this component, we can reuse it across multiple pages.

4. Basic slot usage

  • Using special elements in a child component opens a slot for the child component. What is inserted into the slot depends on how the parent component uses it. Here is an example of defining a slot for a child component: The content in the slot represents the content that is displayed by default if nothing is inserted into the component.

5. Named slot

  • When the function of the child component is complex, the slot of the child component may not be one. For example, if we were to encapsulate a child component of the navigation bar, we would need three slots, one for left, one for center, and one for right. At this point we need to give the slot a name:

    <slot name='myslot'></slot>

3. However, there are different kinds of tabber components for different pages, so how to encapsulate such tabber components?

  1. If we were to encapsulate each component separately, the display would be inappropriate, but if we were to encapsulate one component, it would also be inappropriate

    For example, if every page is returned, we need to repeat this part of the content to encapsulate. Some have menus on the left, some have return, some have search in the middle, some have text, and so on.

  2. So how do you encapsulate it? Extract the commonalities and retain the differences

    The best encapsulation is to extract commonalities into components and expose differences as slots. Once we've reserved the slot, we let the user decide what to insert into the slot according to their needs. Is it the search box, is it the text, is it the menu. It can be decided by the caller

  3. How it should be encapsulated

    • A self-defined TabBar component that is used in the App
    • Have the TabBar at the bottom and set the related styles
  4. What is displayed in the TabBar is determined by the outside world

    • Using slot
    • The Flex layout bisects the TabBar
  5. Custom TabBarItem that can be passed in images and text

    • Define TabBarItem, and define three slots: image (before and after click), and text
    • Wrap the three slots around divs, to prevent the related classes from being overwritten when the user uses them, and to use for styling
    • Fill the slot to achieve the effect of a bottom TabBar

4.TabBar- Build the basic structure

  1. Below is the basic structure of the Tabbar we need to build

  1. The vUE scaffolding needs to be installed before the start. You can refer to the official version of VUE, cn.vuejs.org/, where I use vuecli2.

  2. Create a new project vue Init Webpack Tabbar

  3. Fill in the project description, author, and install vue-Router

  4. I’m going to copy all the resources I’m going to use into the project. Here I’m going to copy the images into the SRC /assets/img/tabbar directory. Under SRC, I created a pages directory to store the components for each page. Check out my directory

  1. Because the home page has changed its location, the index.js inside the router needs to be changed to

5. The first component is TabBar

How to create the component Tabbar, which is the toolbar at the bottom of the mobile, and this is how it will be implemented.

  1. First, the component is divided into two parts: the first is the outer container of the component, the second is the component’s child container item, and the component is divided into the image and text combination. The subcomponent has two states, one is gray by default and the other is selected. Then, under the Components folder, create two new components to implement our TAB component at the bottom: one is tabbarItem. vue, which implements the item item of the child component.
  2. TabBarItem.vue
<template>
  <div class="tab-bar-item"> <! -- The slot will be replaced directly, so it's better to wrap a div around the slot --> <div> <slot name="item-icon"></slot></div>
    <div> <slot  name="item-icon-active"></slot> </div>
    <div> <slot name="item-text"></slot> </div> </div> </template> <style > .tab-bar-item{ flex: 1; text-align: center; height: 49px; font-size: 14px; } .tab-bar-item img{ width: 24px; height: 24px; margin-top: 3px; /* vertical-align: bottom; } .active { color: rgb(255, 0, 149); } </style>Copy the code
  1. One is tabbar. vue, which implements TAB’s outer container
<template>
   <div id="tab-bar">
      <slot></slot>
    </div>
</template>

<script>
export default {

}
</script>

<style scoped>
#tab-bar{
  display: flex;
  background-color: #f6f6f6;position: fixed; left: 0; right: 0; bottom: 0; The box - shadow: 0 px 1 px 1 px rgba (100100100, 1); } </style>Copy the code
  1. Create mainTabbar. vue in the Components folder and combine the two components to achieve TAB effect
<template>
   <tab-bar>
      <tab-bar-item  >
        <img slot="item-icon" src="@/assets/img/tabbar/shouye.png" alt="">
        <div slot="item-text"> < span style = "box-sizing: border-box; color: RGB (62, 62, 62); line-height: 22px; white-space: inherit;"item-icon" src="@/assets/img/tabbar/icon_category.png" alt="">
        <div slot="item-text"> </tab-bar-item> <tab-bar-item> <img slot="item-icon" src="@/assets/img/tabbar/gouwuche.png" alt="">
        <div slot="item-text"> Shopping cart </div> </tab-bar-item> <tab-bar-item > <img slot="item-icon" src="@/assets/img/tabbar/wode.png" alt="">
        <div slot="item-text"> my </div> </tab-bar-item> </tab-bar> </template> <script> import TabBar from'@/components/tabbar/TabBar';
import TabBarItem from '@/components/tabbar/TabBarItem';
export default {
  components: {
    TabBar,
    TabBarItem
  }
}
</script>

<style>

</style>

Copy the code
  1. The finished renderings

6. Click Switch to switch to the routing page

To realize the click switch of the child component to change the state, it is switched between the two pictures. The user directly sends the two pictures at the same time, and the underlying package will automatically switch.

  1. First the user adds the selected active image
<template>
   <tab-bar>
      <tab-bar-item >
        <img slot="item-icon" src="@/assets/img/tabbar/shouye.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/shouye-2.png" alt="">
        <div slot="item-text"> < span style = "box-sizing: border-box; color: RGB (62, 62, 62); line-height: 22px; white-space: inherit;"item-icon" src="@/assets/img/tabbar/icon_category.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/icon_category-2.png" alt="">
        <div slot="item-text"> </tab-bar-item> <tab-bar-item > <img slot="item-icon" src="@/assets/img/tabbar/gouwuche.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/gouwuche-2.png" alt="">
        <div slot="item-text"> Shopping cart </div> </tab-bar-item> <tab-bar-item> <img slot="item-icon" src="@/assets/img/tabbar/wode.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/wode-2.png" alt="">
        <div slot="item-text"> my </div> </tab-bar-item> </tab-bar> </template> <script> import TabBar from'@/components/tabbar/TabBar';
import TabBarItem from '@/components/tabbar/TabBarItem';
export default {
  components: {
    TabBar,
    TabBarItem
  }
}
</script>


Copy the code
  1. The v-if and V-else in tabbarItem. vue determine which image the user needs
<template>
  <div class="tab-bar-item"> <! -- The slot will be replaced directly, so it's better to wrap a div --> <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: false, } } } </script> <style > .tab-bar-item{ flex: 1; text-align: center; height: 49px; font-size: 14px; } .tab-bar-item img{ width: 24px; height: 24px; margin-top: 3px; /* vertical-align: bottom; } .active { color: rgb(255, 0, 149); } </style>Copy the code
  1. The ue-router route was used to switch pages. Procedure
    • Create folder components for each of the four pages under the Pages page
    • Setting route Hops on the Router (using lazy loading)
import Vue from 'vue'
import Router from 'vue-router';

const Home = () => import('.. /pages/home/Home')
const Cart = () => import('.. /pages/cart/Cart')
const Profile = () => import('.. /pages/profile/Profile')
const Category = () => import('.. /pages/category/Category')

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: '/home'
    },
    {
      path:'/home',
      component: Home
    },
    {
      path:'/cart',
      component: Cart
    },
    {
      path:'/profile',
      component: Profile
    },
    {
      path:'/category',
      component: Category
    },
  ],
  mode: 'history'
})

Copy the code
    • Add paths to each subcomponent of mainTabbar. vue
<tab-bar>
      <tab-bar-item path="/home" >
        <img slot="item-icon" src="@/assets/img/tabbar/shouye.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/shouye-2.png" alt="">
        <div slot="item-text"> </div> </tab-bar-item> <tab-bar-item path="/category" "> item-icon" src="@/assets/img/tabbar/icon_category.png" alt=""> item-icon-active" src="@/assets/img/tabbar/icon_category-2.png" alt=""> item-text">   /cart"> item-icon" src="@/assets/img/tabbar/gouwuche.png" alt=""> item-icon-active" src="@/assets/img/tabbar/gouwuche-2.png" alt=""> item-text  /profile"">
        <img slot="item-icon" src="@/assets/img/tabbar/wode.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/wode-2.png" alt="">
        <div slot="item-text"< div style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 13px! Important; word-break: inherit! Important;"Copy the code
    • Add a click event to tabbarItem. vue to jump to the page by changing the route
    • Uses props to accept the parent value, which must be of type String
    • If you want to go back, you use push. If you don’t want to go back, you use replace. Here we use this.$router.replace() to jump the route
<template>
  <div class="tab-bar-item" @click="itemClick"> <! -- The slot will be replaced directly, so it's better to wrap a div --> <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,
  },
  computed: {
    isActive() {
      // /home -> item1(/home) =true/ / for otherwisefalse/ / indexOf! Equals equals minus 1return this.$route.path.indexOf(this.path) ! == -1 }, }, methods: {itemClick() {// If you want the user to return, use push. If you don't, use replace this.$router.replace(this.path); } } } </script> <style > .tab-bar-item{ flex: 1; text-align: center; height: 49px; font-size: 14px; } .tab-bar-item img{ width: 24px; height: 24px; margin-top: 3px; /* vertical-align: bottom; } .active { color: rgb(255, 0, 149); } </style>Copy the code

7.TabBar color dynamic control

  1. When clicking the jump page, you want the text color to be different in each item
    • Insert color through slot in MainTabbar. vue
 <tab-bar>
      <tab-bar-item path="/home" activeColor="blue">
        <img slot="item-icon" src="@/assets/img/tabbar/shouye.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/shouye-2.png" alt="">
        <div slot="item-text"> </div> </tab-bar-item> <tab-bar-item path="/category" activeColor="red">
        <img slot="item-icon" src="@/assets/img/tabbar/icon_category.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/icon_category-2.png" alt="">
        <div slot="item-text"</div> </tab-bar-item> <tab-bar-item path="/cart">
        <img slot="item-icon" src="@/assets/img/tabbar/gouwuche.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/gouwuche-2.png" alt="">
        <div slot="item-text"> Shopping cart </div> </tab-bar-item> <tab-bar-item path="/profile" activeColor="green">
        <img slot="item-icon" src="@/assets/img/tabbar/wode.png" alt="">
        <img slot="item-icon-active" src="@/assets/img/tabbar/wode-2.png" alt="">
        <div slot="item-text"< div style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 13px! Important; word-break: inherit! Important;"Copy the code
  1. Dynamically add color to text by calculating properties in tabbarItem. vue
<template>
  <div class="tab-bar-item" @click="itemClick"> <! -- The slot will be replaced directly, so it's better to wrap a div --> <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 {
      // isActive: false,
    }
  },
  computed: {
    isActive() {
      // /home -> item1(/home) =true/ / for otherwisefalse/ / indexOf! Equals equals minus 1return this.$route.path.indexOf(this.path) !== -1
    },
    activeStyle() {
      return this.isActive ? {color: this.activeColor} : {}
    }
  },
  methods: {
    itemClick() {// If you want the user to return, use push. If you don't, use replace this.$router.replace(this.path); } } } </script> <style > .tab-bar-item{ flex: 1; text-align: center; height: 49px; font-size: 14px; } .tab-bar-item img{ width: 24px; height: 24px; margin-top: 3px; /* vertical-align: bottom; } </style>Copy the code

8. Dynamic demonstration