转载自https://blog.csdn.net/wang1006008051/article/details/78686451?utm_source=blogxgwz6

Vue导航栏

        用Vue写手机端的项目,经常会写底部导航栏,我这里总结一套比较方便实用的底部导航栏方法,并且可以解决浏览器刷新选中状态消失的问题。也可以选择自适应屏幕。看一下效果,底部的图标全是UI给的选中和未选中样式的图片,根据公司要求,你也可能会用fontsize去写。(全部代码黏贴到本文的最后面了)


1、首先把这些小图片放到src/assets路径下面(自动base64编码)





2、在data()里边定义一个选中对应的变量isSelect,和循环遍历的数组,数组下面放图标对应的文字,和选中,未选中的图片地址。   注意:图片的地址不要直接写,直接写就是字符串,不仅会出现显示不出图片的情况,而且打包之后,还是这里地址,不会变。使用webpack提供的require引入图片地址就可以解决以上问题。


  
  
  1. data () {
  2. return {
  3. isSelect: '首页',
  4. nav: [
  5. {title: '首页', url: require('../../assets/common/首页@2x.png'), url_one: require('../../assets/common/首页_active@2x.png')},
  6. {title: '店铺', url: require('../../assets/common/店铺@2x.png'), url_one: require('../../assets/common/店铺_active@2x.png')},
  7. {title: '创业直播', url: require('../../assets/common/直播@2x.png'), url_one: require('../../assets/common/直播_active@2x.png')},
  8. {title: '我的', url: require('../../assets/common/我的@2x.png'), url_one: require('../../assets/common/我的_active@2x.png')}
  9. ]
  10. }
  11. },

html遍历这个nav数组,并且给每个li注册点击事件selectNav(),参数就是title。


  
  
  1. <ul>
  2. <li v-for="item in nav" @click="selectNav(item.title)">
  3. <img :src="isSelect === item.title ? item.url_one : item.url" alt="item.title">
  4. <p :class="isSelect === item.title ? 'active' : ''">{{item.title}} </p>
  5. </li>
  6. </ul>

在methods中定义这个事件


  
  
  1. methods: {
  2. selectNav (title) {
  3. this.isSelect = title
  4. }

3、这个方法里还可以根据title的值去跳转到相应的路由,这样一个基本的底部导航栏就是实现了。

  
  
  1. methods: {
  2. selectNav (title) {
  3. this.isSelect = title
  4. switch (title) {
  5. case '首页': this.$router.push('/index')
  6. break
  7. case '店铺': this.$router.push('/shop')
  8. break
  9. case '创业直播': this.$router.push('/live')
  10. break
  11. case '我的': this.$router.push('/my')
  12. break
  13. }
  14. sessionStorage.setItem('isSelect', this.isSelect)
  15. }
  16. }

但是 电脑调试的时候会发现,刷新浏览器后,选中的状态就会消失。(你可能会觉得用户一般不会在手机端刷新页面/或者直接输入路由跳转到相应的页面,如果要追求完美的,请继续往下看微笑
比如,我选中的状态是创业直播:



当我点击刷新页面后,就会返回到默认的首页状态,如下。



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


  
  
  1. mounted () {
  2. this.isSelect = sessionStorage.getItem('isSelect')
  3. },
  4. methods: {
  5. selectNav (title) {
  6. this.isSelect = title
  7. sessionStorage.setItem('isSelect', this.isSelect)
  8. }
  9. }

经过测试,新的问题又发现了,比如当前在“创业直播”这个状态上,我在浏览器上直接输入“http://localhost:8080/#/shop”,这样用上面的办法就解决不了问题了。最好的办法就是和路由绑定无论点击,还是浏览器上输入路由改变,都正确显示选中状态。

在router/index.js里边映射组件路由时,加上对应的name


   
   
  1. routes: [
  2. {
  3. path: '/',
  4. redirect: '/index'
  5. },
  6. {
  7. path: '/index',
  8. name: '首页',
  9. component: index
  10. },
  11. {
  12. path: '/live',
  13. name: '创业直播',
  14. component: live
  15. },
  16. {
  17. path: '/my',
  18. name: '我的',
  19. component: my
  20. },
  21. {
  22. path: '/shop',
  23. name: '店铺',
  24. component: shop
  25. }
  26. ]

mounted钩子里边的代码改为:


   
   
  1. mounted () {
  2. this.isSelect = this.$route.name
  3. },

methods方法里边的代码修改为


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


  
  
  1. * rem计算方式:设计图尺寸px / 100 = 实际rem 【例: 100px = 1rem,32px = .32rem】
  2. */
  3. !function (window) {
  4. /* 设计图文档宽度 */
  5. var docWidth = 750;
  6. var doc = window.document,
  7. docEl = doc.documentElement,
  8. resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
  9. var recalc = (function refreshRem () {
  10. var clientWidth = docEl.getBoundingClientRect().width;
  11. /* 8.55:小于320px不再缩小,11.2:大于420px不再放大 */
  12. docEl.style.fontSize = Math.max(Math.min(20 * (clientWidth / docWidth), 11.2), 8.55) * 5 + 'px';
  13. return refreshRem;
  14. })();
  15. /* 添加倍屏标识,安卓为1 */
  16. docEl.setAttribute('data-dpr', window.navigator.appVersion.match(/iphone/gi) ? window.devicePixelRatio : 1);
  17. if (/iP(hone|od|ad)/.test(window.navigator.userAgent)) {
  18. /* 添加IOS标识 */
  19. doc.documentElement.classList.add('ios');
  20. /* IOS8以上给html添加hairline样式,以便特殊处理 */
  21. if (parseInt(window.navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/)[1], 10) >= 8)
  22. doc.documentElement.classList.add('hairline');
  23. }
  24. if (!doc.addEventListener) return;
  25. window.addEventListener(resizeEvt, recalc, false);
  26. doc.addEventListener('DOMContentLoaded', recalc, false);
  27. }(window);

使用方法:

把视觉稿中的px转换成rem;

 rem计算方式:设计图尺寸px / 100 = 实际rem 【例: 100px = 1rem,32px = 0.32rem】;

 特别注意:是不需要再除以2的!

无论设计图什么尺寸,算法一致。但需修改js 中 docWidth 变量为设计图宽度;默认设计图文档宽度为750px; 一些不使用rem的CSS属性。包括但不限于:border-widthborder-radiusbox-shadowtransformbackground-size



附录底部导航栏的代码(样式使用了less预编译):

  
  
  1. <template>
  2. <div class="common_foot">
  3. <ul>
  4. <li v-for="item in nav" @click="selectNav(item.title)">
  5. <img :src="isSelect === item.title ? item.url_one : item.url" alt="item.title">
  6. <p :class="isSelect === item.title ? 'active' : ''">{{item.title}} </p>
  7. </li>
  8. </ul>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. data () {
  14. return {
  15. isSelect: '首页',
  16. nav: [
  17. { title: '首页', url: require( '../../assets/common/首页@2x.png'), url_one: require( '../../assets/common/首页_active@2x.png')},
  18. { title: '店铺', url: require( '../../assets/common/店铺@2x.png'), url_one: require( '../../assets/common/店铺_active@2x.png')},
  19. { title: '创业直播', url: require( '../../assets/common/直播@2x.png'), url_one: require( '../../assets/common/直播_active@2x.png')},
  20. { title: '我的', url: require( '../../assets/common/我的@2x.png'), url_one: require( '../../assets/common/我的_active@2x.png')}
  21. ]
  22. }
  23. },
  24. mounted () {
  25. this.isSelect = this.$route.name
  26. },
  27. methods: {
  28. selectNav (title) {
  29. switch (title) {
  30. case '首页': this.$router.push( '/index')
  31. break
  32. case '店铺': this.$router.push( '/shop')
  33. break
  34. case '创业直播': this.$router.push( '/live')
  35. break
  36. case '我的': this.$router.push( '/my')
  37. break
  38. }
  39. this.isSelect = this.$route.name
  40. }
  41. }
  42. }
  43. </script>
  44. <style lang="less" scoped>
  45. .common_foot>ul{
  46. position: fixed;
  47. bottom: 0;
  48. z-index: 1000;
  49. height: 0.98rem;
  50. width: 100%;
  51. overflow: hidden;
  52. background-color: white;
  53. li{
  54. float: left;
  55. width: 25%;
  56. height: 100%;
  57. text-align: center;
  58. cursor: pointer;
  59. padding: 0.15rem 0 0.13rem 0;
  60. }
  61. p{font-size: 0.2rem;color: #7f7f7f;}
  62. img{
  63. width: 0.48rem;
  64. height: 0.45rem;
  65. }
  66. .active{
  67. color: #ffd100;
  68. }
  69. }
  70. </style>


Logo

前往低代码交流专区

更多推荐