vue component encapsulation - tabBar bottom navigation bar

Posted by cbrknight on Tue, 02 Nov 2021 16:15:42 +0100

design sketch:

  Component code:

<template>
  <!-- Customize the bottom menu bar===>Simulate applet menu bar effect -->
  <div class="tabbar">
    <!--  Space occupying container===>The page setup placeholder container is designed to offset the fixed positioning height of the bottom navigation bar. -->
    <div class="placegolder-container"></div>
    <!-- Bottom navigation bar -->
    <div class="bottom-tabs">
      <!-- tabsList ==> Menu column source data -->
      <!-- tabsChange(index)==>Bottom navigation bar route switching click event==>Pass in the currently clicked index -->
      <div
        class="tabs-item"
        v-for="(item, index) in tabsList"
        :key="index"
        @click="tabsChange(index)"
      >
        <!-- tabIndex Mark the currently selected route to switch the menu column -->
        <!-- Not available === Otherwise, the matching will not succeed, possibly because index The types of values are different. All values cannot be exactly equal -->
        <img
          class="tab-tabBarIcon"
          :src="tabIndex == index ? item.SelectedSrc : item.notSelectedSrc"
        />
        <p class="tab-text" :class="tabIndex == index ? 'active' : ''">
          {{ item.text }}
        </p>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Tabbar',
  components: {},
  data () {
    return {
      tabIndex: 0,
      tabsList: [
        {
          //!  Use in html: src dynamically sets the path of img. You need to use require to set the static path, otherwise it will be treated as a string and the picture address cannot be resolved
          notSelectedSrc: require('@/assets/tabBarIcon/workSpace.png'),
          SelectedSrc: require('@/assets/tabBarIcon/workSpace-action.png'),
          text: 'workbench',
          path: '/workingSpace'
        },
        {
          notSelectedSrc: require('@/assets/tabBarIcon/fsl.png'),
          SelectedSrc: require('@/assets/tabBarIcon/fsl-action.png'),
          text: 'Item 1',
          path: '/workingSpace'
        },
        {
          notSelectedSrc: require('@/assets/tabBarIcon/fsl.png'),
          SelectedSrc: require('@/assets/tabBarIcon/fsl-action.png'),
          text: 'Item 1',
          path: '/workingSpace'
        }
      ]
    }
  },
  created () {
    // As soon as you open the page, go to get the [menu selected value] stored in localStorage
    // !==> Using localStorage to store, you can still keep (selected / activated) when refreshing the page
    if (localStorage.getItem('tabIndex')) {
      this.tabIndex = localStorage.getItem('tabIndex')
      // console.log('the previously selected bottom menu bar is: = = > ', this. TabIndex)
    }
  },
  methods: {
    // Click tabbar to trigger the event
    tabsChange (index) {
      // console.log('click tabbar = = ', index)
      // The index assigned to the selected element in data is used to switch the effect
      this.tabIndex = index
      // Jump to the page according to the route of the selected element
      this.$router.push({
        path: this.tabsList[index].path
      })
      // Set the index of the currently selected menu bar element to localStorage
      localStorage.setItem('tabIndex', this.tabIndex)
    }
  },
  /**
   * About meta configuration of routing in router
    import Login from '../views/Login.vue'
    import CheckList from '../views/CheckListOfList/CheckList.vue'
    ...
    {
      path: '/xxx',
      component: Xxx,
      name: 'xx',
      meta: {
        //*?The index corresponding to the route you set. When the web page directly accesses the route, you can also get the index by listening to the router's meta in the page
        index: 0,
        //*It means that this route does not need to log in. How to judge? You should listen on the page or get the self set field in meta in [route Guard] to judge
        needLogin: false,
        title: 'xxx'
      }
    }
   */
  // !  The purpose of watch monitoring is to monitor and obtain the index set in the meta in the route to determine which menu index to activate and store when using [browser forward and backward]
  watch: {
    /**
     * watch Listen to $route. If you use it directly, you can only listen to routes with children. If you want to listen to routes without child nodes, you need to
     // Deep observation and monitoring
      deep: true,
      //? Directly trigger once, otherwise it can't be monitored
      immediate: true
     */
    $route: {
      handler: function (newval, oldVal) {
        // console.log('listen to new value of route: ')
        // console.log(newval)
        // ! After listening to the router of the current page containing index, assign it to data and set the activation style of tabbar
        if (newval.meta.index) {
          this.tabIndex = newval.meta.index
          localStorage.setItem('tabIndex', this.tabIndex)
        }
      },
      // Deep observation and monitoring
      deep: true,
      // Direct trigger once
      immediate: true
    }
  }
}
</script>

<style scoped lang="less">
.tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
}
.placegolder-container {
  height: 60px;
}

.bottom-tabs {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 5;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  box-shadow: 0px -1px 1px #e6e6e6;
  background-color: #fff;

  .tabs-item {
    flex: 1;
    height: 60px;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;

    .tab-tabBarIcon {
      width: 30px;
      height: 30px;
      border-radius: 4px;
    }

    .tab-text {
      font-size: 14px;
      margin: 0;

      &.active {
        color: #007aff;
      }
    }
  }
}
</style>

Note: the icon image of the menu needs to be prepared in advance

  

Using components:

import Tabbar from '@/components/TabBarComponent.vue'
. . . . 
 
<!-- Bottom navigation tabbar column -->
    <Tabbar></Tabbar>

The icon of tabBar should be placed by yourself first, otherwise there is no picture. Of course, you can also change it to icon and download it from Ali icon library. You can see these two blogs on how to download color icons through Ali Icon Library:

vue reference Ali color icon (symbol reference)_ Five speed headless blog - CSDN blog has three ways to reference Ali icon library. The first two can only introduce monochrome icons. It's easy for obsessive-compulsive disorder, so I refer to other big guys' blogs and learn how to reference colored icons through symbol. The first step: select the icons you want in Ali Icon Library, add them to the shopping cart and add them to the project, Download to local. This will download the style files locally. Step 2: create the corresponding inconfont folder in the vue project, and put these downloaded style files into the new file to facilitate reference in the project. Step 3: import these files in main.js (the first two are Ali icon files, and the last one can be omitted, just the width and height of the basic icon set by yourself). The purpose is to make the wholehttps://blog.csdn.net/black_cat7/article/details/120322471vue references Ali color icon (symbol reference) - encapsulates its own icon component five speed headless monster blog - CSDN blog. For how to introduce color Ali icon, please refer to another blog: vue references Ali color icon (symbol reference) _Five speed headless blog - CSDN blog https://blog.csdn.net/black_cat7/article/details/120322471 Next, you need to encapsulate your own icon component for easy use. Step 1: create a new component in the components file (my name is cjIcon.vue) < template > <! -- symbol refers to the color icon, so you have to write -- > <! --: clashttps://blog.csdn.net/black_cat7/article/details/120324789 

Topics: Vue Vue.js