vue组件封装-tabBar底部导航栏

效果图:

 

 组件代码:

<template>
  <!-- 自定义底部菜单栏===》模拟小程序菜单栏效果 -->
  <div class="tabbar">
    <!--  占位容器===》页面设置占位容器是为了抵消底部导航栏固定定位的高度。 -->
    <div class="placegolder-container"></div>
    <!-- 底部导航栏 -->
    <div class="bottom-tabs">
      <!-- tabsList ==》 菜单栏目源数据 -->
      <!-- tabsChange(index)==》底部导航栏路由切换点击事件==》传入当前点击的index -->
      <div
        class="tabs-item"
        v-for="(item, index) in tabsList"
        :key="index"
        @click="tabsChange(index)"
      >
        <!-- tabIndex 标记当前选中的路由,用于切换菜单栏目 -->
        <!-- 不可使用 === 否则会无法匹配成功,可能是因为index值的类型不一样所有无法完全相等 -->
        <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: [
        {
          //! html中使用 :src 动态设置img的路径,需要使用require来设置静态路径,否则会被当作字符串,无法解析图片地址
          notSelectedSrc: require('@/assets/tabBarIcon/workSpace.png'),
          SelectedSrc: require('@/assets/tabBarIcon/workSpace-action.png'),
          text: '我的工作台',
          path: '/workingSpace'
        },
        {
          notSelectedSrc: require('@/assets/tabBarIcon/fsl.png'),
          SelectedSrc: require('@/assets/tabBarIcon/fsl-action.png'),
          text: '防渗漏报验',
          path: '/fslHome'
        }
      ]
    }
  },
  created () {
    // 一打开页面,就去获取存储在sessionStorage中的 【菜单选中值】
    // !==》使用sessionStorage来存储,在刷新页面的时候,依然可以保持(选中/激活)状态
    if (sessionStorage.getItem('tabIndex')) {
      this.tabIndex = sessionStorage.getItem('tabIndex')
      // console.log('之前选中的底部菜单栏是:====>', this.tabIndex)
    }
  },
  methods: {
    // 点击tabbar触发事件
    tabsChange (index) {
      // console.log('点击tabbar==》', index)
      // 赋值给data中选中的元素的index,用于切换效果
      this.tabIndex = index
      // 根据选中的元素的路由,来跳转页面
      this.$router.push({
        path: this.tabsList[index].path
      })
      // 设置当前选择的菜单栏元素的index到sessionStorage中去
      sessionStorage.setItem('tabIndex', this.tabIndex)
    }
  },
  /**
   * 关于 router中配置路由的meta
    import Login from '../views/Login.vue'
    import CheckList from '../views/CheckListOfList/CheckList.vue'
    ...
    {
      path: '/xxx',
      component: Xxx,
      name: 'xx',
      meta: {
        //*?自己设置的这个路由对应的index,当网页直接访问到这个路由时,也能在页面里通过监听router的meta来获取到这个index
        index: 0,
        //*表示这个路由不需要登录,具体要怎么判断,要自己在页面监听或者在【路由守卫】里取到meta里的这个自己设置的字段,来判断
        needLogin: false,
        title: 'xxx'
      }
    }
   */
  // ! watch 监听的目的是为了在使用【浏览器前进后退】的时候,去监听获取router路由中的meta中设置的index来判断要激活、存储哪个菜单的index
  watch: {
    /**
     * watch 监听 $route,如果直接用,只能监听有children的路由,如果要监听没有子节点的路由,需要
     // 深度观察监听
      deep: true,
      //? 直接触发一次 ,否则监听不到
      immediate: true
     */
    $route: {
      handler: function (newval, oldVal) {
        // console.log('监听到路由的新值:')
        // console.log(newval.meta.index)
        // !监听到当前页面的router中含有index,就赋值给data,设置tabbar的激活样式
        // @注意,此处需要加上 ||(或者) 这个判断 因为0本身就相当于false,所以当router的index是0,就无法触发这个if了,所以要加上这个或者的判断
        if (newval.meta.index || newval.meta.index === 0) {
          this.tabIndex = newval.meta.index
          // console.log('当前tabbar的新值:')
          // console.log(this.tabIndex)
          sessionStorage.setItem('tabIndex', this.tabIndex)
        }
      },
      // 深度观察监听
      deep: true,
      // 直接触发一次
      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>

注意:菜单的图标图片需要自己提前准备好

  

注意:监听路由中的index时,要注意index=0的情况,需要单独判断为0的情况


 

使用组件:

import Tabbar from '@/components/TabBarComponent.vue'
。。。。
 
<!-- 底部导航tabbar栏 -->
    <Tabbar></Tabbar>

tabBar的图标,要先自己放好,不然是没有图片的,当然,你也可以改成icon,去阿里图标库下载,如何通过阿里图标库下载彩色图标,可以看这两篇博客:

vue引用阿里彩色图标(symbol引用)_五速无头怪的博客-CSDN博客引用阿里图标库的方式有三种,前两种都只能引入单色的图标,对于强迫症简直了,所以俺参考其他大佬的博客,学习了如何通过symbol引用彩色的图标第一步:在阿里图标库选择好自己要的图标,加入购物车,添加至项目,下载到本地这样就把样式文件下载到本地了第二步:在vue项目里面创建对应的inconfont文件夹将这些下载的样式文件放到新建的文件里,方便项目中引用第三步:在main.js中,引入这几个文件(前两个是阿里图标文件,最后一个可以不要,只是自己设置的基础图标宽高等),目的是为了让全...https://blog.csdn.net/black_cat7/article/details/120322471vue引用阿里彩色图标(symbol引用)-封装自己的icon组件_五速无头怪的博客-CSDN博客关于如何引入彩色的阿里图标,请参考另一篇博客:vue引用阿里彩色图标(symbol引用)_五速无头怪的博客-CSDN博客https://blog.csdn.net/black_cat7/article/details/120322471接下来要封装出自己的icon组件,方便使用。第一步:在components文件中新建一个组件(我的叫cjIcon.vue)<template> <!-- symbol方式引用彩色图标,就得这么写 --> <!-- :clashttps://blog.csdn.net/black_cat7/article/details/120324789 


代码中我都写了注释,基本都做了说明,可以看懂的~

有几个地方需要注意:

1.  router路由的监听与设置      

        这个组件有watch监听页面的router路由,因为网页是可以通过路由来跳转页面的,如果用户直接通过router路由跳转到tabBar菜单页面,那么就相当于没有点击过菜单,没法触发选中效果,所以通过监听路由,并且在touter.js文件中,给对应的路由设置index键值对,用来判断

 router中设置的index,要跟组件中设置的菜单数据顺序一致,因为是通过这个顺序来比对后判断要选中哪个菜单的


 2.图标图片地址的引用路径不能使用绝对路径

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DTcode7

你的鼓励是我坚持的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值