vue底部导航栏(选中状态刷新不消失)解决

我们用Vue写手机端的项目,经常会写底部导航栏,我这里总结一套比较方便实用的底部导航栏方法,并且可以解决浏览器刷新选中状态消失的问题。也可以选择自适应屏幕。看一下效果,底部的图标是我自己找的,选中和未选中样式的图片,根据公司要求,你也可能会用fontsize去写。(全部代码黏贴到本文的最后面了)
在这里插入图片描述
关于布局的已经写过了,在这个博客文件中.
当然还有新的方法去写导航
首先在导航页面中的data()里边定义一个选中对应的变量isSelect,和循环遍历的数组,数组下面放图标对应的文字,和选中,未选中的图片地址。 注意:图片的地址不要直接写,直接写就是字符串,不仅会出现显示不出图片的情况,而且打包之后,还是这里地址,不会变。使用webpack提供的require引入图片地址就可以解决以上问题。

Nav.vue 文件

   data () {
      return {
        isSelect: '首页', // 默认首选页面是首页
        nav: [
          {title: '首页', url: require('../../assets/common/首页@2x.png'), url_one: require('../../assets/common/首页_active@2x.png')},
          {title: '分类', url: require('../../assets/common/分类@2x.png'), url_one: require('../../assets/common/分类_active@2x.png')},
          {title: '米圈', url: require('../../assets/common/米圈@2x.png'), url_one: require('../../assets/common/米圈_active@2x.png')},
          {title: '购物车', url: require('../../assets/common/购物车@2x.png'), url_one: require('../../assets/common/购物车_active@2x.png')},
          {title: '我的', url: require('../../assets/common/我的@2x.png'), url_one: require('../../assets/common/我的_active@2x.png')}
        ]
      }
    },

设置了基本的数据
那我们在template 中

<template>
 <div class="Nav">
  	  <ul>
	      <li v-for="item in nav" @click="selectNav(item.title)">
	        <img :src="isSelect === item.title ? item.url_one : item.url" alt="item.title">
	        <p :class="isSelect === item.title ? 'active' : ''">{{item.title}}</p>
	      </li>
	   </ul>  
  </div>
</template>

那么我们在script 中写入

	 methods: {
      selectNav (title) { // 选中的是哪个路由导航
        this.isSelect = title
      }
     这个方法里还可以根据title的值去跳转到相应的路由,这样一个基本的底部导航栏就是实现了。
     或者
     methods: {
      selectNav (title) {
        this.isSelect = title
        switch (title) {
          case '首页': this.$router.push('/home')
            break
          case '分类': this.$router.push('/classify')
            break
          case '米圈': this.$router.push('/ring')
            break
          case '购物车': this.$router.push('/shop')
            break
          case '我的': this.$router.push('/mine')
            break
        }
        sessionStorage.setItem('isSelect', this.isSelect) // 存入sessionStorage里面
      }
    }
   但是 电脑调试的时候会发现,刷新浏览器后,选中的状态还是有可能会消失。

解决办法:
每次点击切换底部导航的时候,把选中的状态存入sessStorage里边。在mounted钩子里把这个状态在取出来赋值给这个isSelect变量就可以实现选中状态不消失了。

mounted () {
  this.isSelect = sessionStorage.getItem('isSelect')
},
methods: {
  selectNav (title) {
    this.isSelect = title
    sessionStorage.setItem('isSelect', this.isSelect)
  }
}

但是经过测试,新的问题又发现了,比如当前在“米圈”这个状态上,我在浏览器上直接输入“http://localhost:8080/#/ring”,这样用上面的办法就解决不了问题了。最好的办法就是和路由绑定无论点击,还是浏览器上输入路由改变,都正确显示选中状态。
就是在router/index.js里边映射组件路由时,加上对应的name ,最好用英文

  routes: [
    {
      path: '/',
      redirect: '/home'
    },
    {
      path: '/home',
      name: '首页',
      component:() => import('../views/Home.vue')
    },
    {
      path: '/classify',
      name: '分类',
      component:() => import('../views/Classify.vue')
    },
    {
	  path: '/ring',
      name: '米圈',
      component: () => import('../views/Ring.vue')
    },
    {
      path: '/shop',
      name: '购物车',
      component: () => import('../views/Shop.vue')
    },
    {
      path: '/mine',
      name: '我的', 
      component: () => import('../views/Mine.vue')
    }
  ]

这时候nav.vue文件中mounted钩子和methods方法里边的代码改为:

mounted () {
  this.isSelect = this.$route.name
},
methods: {
  selectNav (title) {
    this.isSelect = this.$route.name
    switch (title) {
    case '首页': this.$router.push('/home')
      break
    case '分类': this.$router.push('/classify')
      break
    case '米圈': this.$router.push('/ring')
      break
    case '购物车': this.$router.push('/shop')
      break
    case '我的': this.$router.push('/mine')
      break
    }
  }
}

注意的是
手机端一般要求自适应各种大小的手机端屏幕,你可以选择用媒体查询,或者js控制font-size。这里我用的是js控制font-size,在index.html引入下面的js。

 * rem计算方式:设计图尺寸px / 100 = 实际rem  【例: 100px = 1rem,32px = 0.32rem】 */
!function (window) {
    /* 设计图文档宽度 */
    var docWidth = 750;
    var doc = window.document,
        docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
    var recalc = (function refreshRem () {
        var clientWidth = docEl.getBoundingClientRect().width;
   		/* 8.55:小于320px不再缩小,11.2:大于420px不再放大 */
    	docEl.style.fontSize = Math.max(Math.min(20 * (clientWidth / docWidth), 11.2), 8.55) * 5 + 'px';
      return refreshRem;
 	})();
    /* 添加倍屏标识,安卓为1 */
    docEl.setAttribute('data-dpr', window.navigator.appVersion.match(/iphone/gi) ? window.devicePixelRatio : 1);
    if (/iP(hone|od|ad)/.test(window.navigator.userAgent)) {
        /* 添加IOS标识 */
        doc.documentElement.classList.add('ios');
        /* IOS8以上给html添加hairline样式,以便特殊处理 */
        if (parseInt(window.navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/)[1], 10) >= 8)
          doc.documentElement.classList.add('hairline');
   	}
    if (!doc.addEventListener) return;
    window.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
}(window);
 // 特别注意:是不需要再除以2的!无论设计图什么尺寸,算法一致。但需修改js 中 docWidth 变量为设计图宽度;默认设计图文档宽度为750px; 一些不使用rem的CSS属性。包括但不限于:border-width、border-radius、box-shadow、transform、background-size;

完整的代码下边就是

<template>
  <div class="common_foot">
    <ul>
      <li v-for="item in nav" @click="selectNav(item.title)">
        <img :src="isSelect === item.title ? item.url_one : item.url" alt="item.title">
        <p :class="isSelect === item.title ? 'active' : ''">{{item.title}}</p>
      </li>
    </ul>
  </div>
</template>
 
<script>
  export default {
    data () {
      return {
        isSelect: '首页',
        nav: [
          {title: '首页', url: require('../../assets/common/首页@2x.png'), url_one: require('../../assets/common/首页_active@2x.png')},
          {title: '分类', url: require('../../assets/common/分类@2x.png'), url_one: require('../../assets/common/分类_active@2x.png')},
          {title: '米圈', url: require('../../assets/common/米圈@2x.png'), url_one: require('../../assets/common/米圈_active@2x.png')},
          {title: '购物车', url: require('../../assets/common/购物车@2x.png'), url_one: require('../../assets/common/购物车_active@2x.png')},
          {title: '我的', url: require('../../assets/common/我的@2x.png'), url_one: require('../../assets/common/我的_active@2x.png')}
        ]
      }
    },
    mounted () {
      this.isSelect = this.$route.name // 重要的在这里和下边,也可以直接用判断 window.location.hash.indexOf('name这里是router里的name' > -1) 然后重新赋值默认选项
      // 用了这个那就不用methods里的方法了,其实都一样
      // 默认是首页了
      /**
       if(window.location.hash.indexOf('fenlei')>-1){ // 
      		this.selectIndex =1 // 分类
      	 } else if (window.location.hash.indexOf('miquan')>-1){
      	    this.selectIndex =2 // 米圈
      	 } else if (window.location.hash.indexOf('gouwuche')>-1){
      	    this.selectIndex =3 // 购物车
      	 } else if (window.location.hash.indexOf('wode')>-1){
      	    this.selectIndex =4 // 我的
      	 } else {
      	   this.selectIndex = 0 // 首页
      	 }
      */
    },
    methods: {
      selectNav (title) {
        this.isSelect = this.$route.name
        switch (title) {
        case '首页': this.$router.push('/home')
          break
        case '分类': this.$router.push('/classify')
          break
        case '米圈': this.$router.push('/ring')
          break
        case '购物车': this.$router.push('/shop')
          break
        case '我的': this.$router.push('/mine')
          break
        }
      }
    }
  }
</script>
 
<style lang="less" scoped>
  .common_foot>ul{
    position: fixed;
    bottom: 0;
    z-index: 1000;
    height: 0.98rem;
    width: 100%;
    overflow: hidden;
    background-color: white;
    li{
      float: left;
      width: 25%;
      height: 100%;
      text-align: center;
      cursor: pointer;
      padding: 0.15rem 0 0.13rem 0;
    }
    p{font-size: 0.2rem;color: #7f7f7f;}
    img{
      width: 0.48rem;
      height: 0.45rem;
    }
    .active{
      color: #ffd100;
    }
  }
</style>

解决了。
当然了还有一个办法,监听

  methods: {
    // 页面切换
    tapPage(index, routeName) {
      this.selectIndex = index; // 下标
      // 编程式路由跳转
      //  是因为vue-router 3.0之后的版本中,push跳转使用了异步的处理
      //    当插入相同的地址信息之后就会报错,可以添加catch对异常做捕获
      this.$router
        .push({
          name: routeName, // 传递路由的name
        })
        .catch(() => {
          // catch对异常做捕获
        });
    },
  },
  // 监听 路由比对,设定index 下标
  watch: {
    $route() {
      if (this.$route.path == "/home") {
        this.selectIndex = 0;
      }
      if (this.$route.path == "/list") {
        this.selectIndex = 1;
      }
      if (this.$route.path == "/cart") {
        this.selectIndex = 2;
      }
      if (this.$route.path == "/user") {
        this.selectIndex = 3;
      }
    },
  },
  // 钩子函数这里也要注意下
  mounted() { // 浏览器路由
    // console.log(window.location);
    // 根据当前的地址信息, 设置选中的图标索引.解决刷新之后的问题
    //  没有使用this.$route.xx 进行设置,因为有些时候获取不到路由信息
    if (window.location.hash.indexOf("home") > -1) {
      this.selectIndex = 0;
    }
    if (window.location.hash.indexOf("list") > -1) {
      this.selectIndex = 1;
    }
    if (window.location.hash.indexOf("cart") > -1) {
      this.selectIndex = 2;
    }
    if (window.location.hash.indexOf("user") > -1) {
      this.selectIndex = 3;
    }
  },
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值