vue页面缓存的实现方以及与原生的部分效果对比

前言

作为移动开发者,相信大家对于使用html开发的App和使用原生Api开发的App,或多或少都有所体验。他们有各自的优势与劣势,今天我们就参考原生App的效果,通过使用vue.js框架来实现一款类似原生效果的应用。

项目简介

联华会员线上退货流程的实现。主要功能点:选店、定位、上传图片、售后查询。实现方案:vue.js

效果预览

23.gif

项目过程中遇到的难点与解决方案

1、原生的页面push跳转是一个从右边往左进入的动画,pop操作是一个从左往右淡出的动画。下面介绍如何使用vue的Router和transition 来达到这种效果。

  • 所有的页面都通过vue-router进行管理,给router-view加一个动画。
<transition :name="transitionName">
      <keep-alive>
        <router-view  class="Router"></router-view>
      </keep-alive>
</transition>
  • 如何获取当前页面是push操作还是pop操作?监听浏览器的popstate 事件。通过在入口文件中监听popstate事件来标记当前的页面是不是pop操作,如果是pop操作就给当前的路由添加一个属性isBack
window.addEventListener('popstate', function (e) {
  router.isBack = true
}, false)
  • 监听路由的isBack属性,给当前页面设置push动画还是pop动画。至此,这种动画效果就实现了。
watch: {
   $route(to, from) {
        // 切换动画
        let isBack = this.$router.isBack
        if (isBack) {
          this.transitionName = 'slide-left'
        } else {
          this.transitionName = 'slide-right'
        }
        this.$router.isBack = false
   }
}

2、页面的缓存与销毁问题
原生的App的push操作会缓存已经加载的页面,pop操作会销毁页面。h5的跳转使用vue-router进行管理,如果不对页面进行特殊的缓存处理,h5的页面会在push时销毁当前页面,重新创建新页面,这种体验明显的不如原生体验,下面我们介绍下如何使用vue的页面缓存机制来达到原生的这种效果。

  • keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能。他有2个常用属性include、exclude属性。include属性表示只有name属性为xxx的组件会被缓存,(注意是组件的名字,不是路由的名字)。exclude属性表示除了name属性为xxx的组件不会被缓存,其它组件都会被缓存。这里我们使用include属性,将push操作的页面缓存起来。

1)第一步:必须设置页面的name属性。

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Main',
      component: Main,
      meta: {
      }
    }
  ]
})

2)第二步:在main.js入口文件中监听router.isBack属性,判断是push还是pop,如果是push就将页面的name存到一个数组中,如果不是就从数组中移除该页面,同时这个数组我们通过vuex存储起来。这个数组中存储的页面就是我们需要缓存的页面。

router.beforeEach((to, from, next) => {
  let isBack = router.isBack
  let arr = store.state.keepAlivePages.slice()
  if (isBack) {
    // 从数组中移除
    let index = arr.indexOf(from.name)
    if (index !== -1) {
      arr.splice(index, 1)
    }
  } else {
    // 加入数组,push操作都要加入缓存数组
    let index = arr.indexOf(from.name)
    if (index === -1) {
      arr.push(from.name)
    }
    let indexTo = arr.indexOf(to.name)
    if (indexTo === -1) {
      arr.push(to.name)
    }
  }
  store.commit('SET_KEEPALIVEPAGES', arr)
  next()
})

3) 最后在主页面中设置我们需要缓存的页面

 <transition :name="transitionName">
      <keep-alive :include="keepAlivePages">
        <router-view class="Router"></router-view>
      </keep-alive>
</transition>

3、如何实现原生界面的侧滑返回效果?

  • 通过判断手势的滑动可以实现侧滑返回的效果,但是和原生的侧滑相比还是有一些效果差距的。需要注意的是在主页面的手势响应可能会影响到滑块Slider的滑动,我们可以在通过修饰符@touchmove.stop 阻止手势的响应,达到不影响Slider的滑动问题。
<template>
  <div id="app" v-on:touchstart="bodyTouchStart" v-on:touchmove="bodyTouchMove" v-on:touchend="bodyTouchEnd">
    <transition :name="transitionName">
      <keep-alive :include="keepAlivePages">
        <router-view class="Router" :style="routerHeightStyle"></router-view>
      </keep-alive>
    </transition>
  </div>
</template>

methods: {
      bodyTouchStart(event) {
        this.touchStartPoint = event.targetTouches[0].pageX
        this.touchStartPointY = event.targetTouches[0].pageY
      },
      bodyTouchMove(event) {
        // 实时计算distance
        this.distance = event.targetTouches[0].pageX - this.touchStartPoint
        this.distanceY = event.targetTouches[0].pageY - this.touchStartPointY
      },
      bodyTouchEnd() {
        // 滚动视图可能会导致左滑,所以要判断y方向的距离
        if (this.distance > 100 && Math.abs(this.distanceY) < 50) {
          this.$refs.navigation.clickBack()
        } else {
        }
        this.distance = 0
      }
}

4、如何实现全局的导航栏?以及导航栏的标题、返回按钮的显示等功能?

  • 在定义路由的时候,我们需要通过meta定义一些可配置的字段,比如是否显示导航栏、导航栏标题、是否显示返回按钮、是否显示Tabbar等等。
{
    path: '/',
    name: 'Home',
    meta: {
      title: '推荐', // 导航栏标题
      showTabbar: true, // 是否显示Tabbar
      showBack: false
    },
    component: resolve => require(['../views/home.vue'], resolve)
},
  • 然后在主页面(一般是App.vue)中设置导航栏等配置
<template>
  <div id="app" v-on:touchstart="bodyTouchStart" v-on:touchmove="bodyTouchMove" v-on:touchend="bodyTouchEnd">
    <!--nav-->
    <navigation
                ref="navigation"
                v-if="!$route.meta.hiddenNav"
                :title="navTitle"
                :showBack="showBack"
                :background="$route.meta.navBackground"
                :showLine="$route.meta.showLine"></navigation>
    <transition :name="transitionName">
      <keep-alive :include="keepAlivePages">
        <router-view  class="Router" :style="routerHeightStyle"></router-view>
      </keep-alive>
    </transition>
    <tabBar v-show="$route.meta.showTabbar"></tabBar>
  </div>
</template>
  • 需要注意的是,在上面的demo中导航栏的标题取的是一个变量navTitle,为什么要通过变量取值?是因为有这样一种场景:比如进入商品详情页面,导航栏的标题是服务器返回的商品名称,这种情况页面已经渲染完成,再通过meta设置标题是没有效果的。所以目前的方案是用通知的方式,把标题传递过来,然后赋值。
mounted() {
      // 动态改变详情页面的title
      this.bus.$on('changeDetailTitle', (title) => {
        this.$set(this.$route.meta, 'title', title)
        this.navTitle = title
      })
}

综述

原生App的体验效果确实优于H5,但是通过以上的各种效果的优化,目前我们的H5项目已经能够更加接近原生的体验效果,特别是页面缓存这一块意义重大。

最后附上效果图,大家注意pop后页面的内容哦,是不是和原生很像.......

24.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容