vue实现导航栏效果(选中状态刷新不消失)

Vue导航栏

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

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


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

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')}
   ]
  }
 },

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

<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>

在methods中定义这个事件

methods: {
   selectNav (title) {
    this.isSelect = title
   }

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

methods: {
   selectNav (title) {
    this.isSelect = title
    switch (title) {
     case '首页': this.$router.push('/index')
      break
     case '店铺': this.$router.push('/shop')
      break
     case '创业直播': this.$router.push('/live')
      break
     case '我的': this.$router.push('/my')
      break
    }
    sessionStorage.setItem('isSelect', this.isSelect)
   }
  }

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

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

解决办法:

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

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

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

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

routes: [
 {
  path: '/',
  redirect: '/index'
 },
 {
  path: '/index',
  name: '首页',
  component: index
 },
 {
  path: '/live',
  name: '创业直播',
  component: live
 },
 {
  path: '/my',
  name: '我的',
  component: my
 },
 {
  path: '/shop',
  name: '店铺',
  component: shop
 }
]

mounted钩子里边的代码改为:

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

methods方法里边的代码修改为

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

 * rem计算方式:设计图尺寸px / 100 = 实际rem 【例: 100px = 1rem,32px = .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);

使用方法:

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

rem计算方式:设计图尺寸px / 100 = 实际rem 【例: 100px = 1rem,32px = 0.32rem】;
 特别注意:是不需要再除以2的!

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

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

<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')}
    ]
   }
  },
  mounted () {
   this.isSelect = this.$route.name
  },
  methods: {
   selectNav (title) {
    this.isSelect = this.$route.name
    switch (title) {
     case '首页': this.$router.push('/index')
      break
     case '店铺': this.$router.push('/shop')
      break
     case '创业直播': this.$router.push('/live')
      break
     case '我的': this.$router.push('/my')
      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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • vue2.0实现导航菜单切换效果

    本文实例为大家分享了vue2.0实现导航菜单切换的具体代码,供大家参考,具体内容如下 css *{ margin:0; padding: 0; } ul li{ list-style: none; } .navul{ margin:100px auto 20px; overflow: hidden; } .navul li{ background-color: #5597b4; padding:18px 30px; float:left; color: #fff; font-size: 18px

  • vue 和vue-touch 实现移动端左右导航效果(仿京东移动站导航)

    先给大家展示下效果图,感觉还不错请参考实现代码: 使用技术:vue2.0 webpack vue-touch 一些简单的javascript; (注意:vue-touch 使用的是2.0.0版本 需要与vue2.0.0兼容) vue-touch(地址:https://github.com/vuejs/vue-touch 注意是next 分支) 左侧导航可滑动(右侧视图窗因为和左逻辑一样 就没写) var VueTouch = require('vue-touch') Lib.Vue.use(Vu

  • vue router仿天猫底部导航栏功能

    首先把天猫的导航贴出来,里面包括精选.品牌.会员.购物车.我五个导航及对应的图标. 分析: 1.图标的获取 进入阿里巴巴矢量图标库,网址  http://www.iconfont.cn. 点击官方图标库,选择天猫图标库,选中放入购物车. 点击添加至项目,点击创建新项目按钮,创建tianmao项目,点击确定. 此时会有查看在线链接和下载至本地两种方式,我选择第一种,因为后期如果要添加小图标的话,只需要重新生成在线链接,然后更新link即可 复制链接到index.html的link标签内,具体为 <

  • vue-router 导航钩子的具体使用方法

    vue-router 提供的导航钩子主要用来拦截导航,让它完成跳转或取消. 全局钩子 1.router.beforeEach 注册一个全局的 before 钩子: const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... }) 每个钩子方法接收三个参数: to: Route: 即将要进入的目标 路由对象 from: Route: 当前导航正要离开的路由 next: Function:

  • 详解vue.js移动端导航navigationbar的封装

    有几天没更新了,这几天上海天气比较热,天气一热就懒得写了.今天感觉还好,就写下导航部分的封装吧. 关于环境搭建和底部tabbar的封装请参考前面的两篇文章 web app和移动端原生app的构架方式不一样的,页面的切换是对整个页面的重新渲染.所以我们每个页面都有自己的导航条. 下面简单封装下导航条 html部分 此处写的导航的三个部分,分别是左边div.中间的title部分div.右边div.代码如下 <template> <header class="m-header&quo

  • vue实现nav导航栏的方法

    每一个网页项目都少不了导航栏,通过原始的方法基本上都是可以写出来的.但是要写出代码量少,冗余度低的代码就要动脑子思考一下了. 最近写了一个百度地图的项目,要求底部有一个导航栏.具体如下图: 首先,拿到了底部导航栏的所有图标图片,图片都有两种.灰色的代表未选中,选中的用带样色的图片替换. 先看一下,组件中 html结构:通过vue提供的v-for方法,进行遍历显示footNav这个数组.数组里边存放着{title:"银行",url:" ",url1:" &q

  • vue 挂载路由到头部导航的方法

    路由是写好了,但正确的切换路由方式不应该是我们在地址栏里面输入地址,有追求的方式是点击头部的导航菜单来切换,就像这样 我们点击上面的发现.关注.消息就切换路由导航 我们先把头部的导航写好 打开header.vue 先把vue组件的基本格式写好 然后开始布局写头部 这里很不好意思,我一直以为头部的header.vue是引入了的,实际上并没有........ 打开app,vue重新编写一下 app.vue 代码: <template> <div id="app">

  • 详解vue-router 2.0 常用基础知识点之导航钩子

    导航钩子 vue-router 提供的导航钩子主要用来拦截导航,让它完成跳转或取消.有多种方式可以在路由导航发生时执行钩子:全局的, 单个路由独享的, 或者组件级的. 全局钩子 const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // do something next(); }); router.afterEach((to, from, next) => { console.log(to.

  • 详解使用Vue Router导航钩子与Vuex来实现后退状态保存

    不好意思,标题比较啰嗦,因为这次的流水账确实属于一个比较细节的小东西,下面详细讲: 1需求 最近在使用electron-vue开发一个跨平台的桌面端软件,刚上手写了几个页面,遇到一个问题:桌面端软件通常会有导航需求,类似下图 导航按钮 点击返回按钮,返回上一页,并且显示上页内容.其实不止App,即使普通的网页中也会有此类需求,尤其是使用vue写SPA时. 项目中的导航几乎都是采用router.push({name: 'xxx', params: {xxx:123...}})这种方式.这种方式导致

  • 非常实用的vue导航钩子

    导航钩子 (译者:『导航』表示路由正在发生改变.) 正如其名,vue-router 提供的导航钩子主要用来拦截导航,让它完成跳转或取消.有多种方式可以在路由导航发生时执行钩子:全局的, 单个路由独享的, 或者组件级的. 全局钩子 你可以使用 router.beforeEach 注册一个全局的 before 钩子: const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... }) 当一个导

随机推荐