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

前言

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

项目简介

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

效果预览

23.gif

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

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

  • 所有的页面都通过vue-router进行管理,给router-view加一个动画。

      
        
      

  • 如何获取当前页面是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) 最后在主页面中设置我们需要缓存的页面

 
      
        
      

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

  • 通过判断手势的滑动可以实现侧滑返回的效果,但是和原生的侧滑相比还是有一些效果差距的。需要注意的是在主页面的手势响应可能会影响到滑块Slider的滑动,我们可以在通过修饰符@touchmove.stop 阻止手势的响应,达到不影响Slider的滑动问题。


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)中设置导航栏等配置

  • 需要注意的是,在上面的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

你可能感兴趣的:(vue页面缓存的实现方以及与原生的部分效果对比)