需求
  vue项目H5页面列表页可以向上滑动加载下一页;当点击跳转详情页时,保留列表页的滚动位置;当从详情页点击跳转二级页面时,保存详情页的滚动位置。

思路:

  1. 列表页的滚动使用的是vux组件库中的Scroller组件,通过观察发现没有滚动条,而是通过样式transform实现的;当跳转详情页的时候缓存列表页可以记录当前位置和数据。
  2. 详情页页面未使用组件,而是通过原生的div平铺下来的内容,超出屏幕可视区域后自动生成滚动条,当跳转子表单页面的时候缓存详情页的数据及位置,发现此时详情页的数据缓存了,但是滚动条的位置并没有被记录,从子表单返回到详情页的时候,详情页还是回到最顶部。
  3. 针对详情页滚动条不能被缓存有以下两种思路:一是,在详情页的div最外层加Scroller组件,此时,详情页面的滚动也通过样式控制,就不存在滚动条了;二是,不需要在最外层加Scroller组件,而是在跳转子表单时记录滚动条位置,在切换回来时给scrollTop重新赋值其滚动位置。

代码:

App.vue

<template>
  <div id="app">
    // 使用keep-alive组件包裹路由
    <keep-alive :include="keepAliveList">
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
  name: 'app',
  // 获取最新的keepAliveList 绑定给include
  computed: {
    ...mapGetters(['keepAliveList']),
  },
  data(){
    return{}
  }
}
</script>

vuex
store/modules/keepAlive.js

const state = {
  // 所有需要被缓存页面name组成的数组
  keepAliveList: []
}

const mutations = {
  // 当pageName不在keepAliveList数组里的时候,就将该pageName存到数组中
  SET_KEEP_ALIVE_LIST: (state, pageName) => {
    if (!state.keepAliveList.includes(pageName)) {
      state.keepAliveList = [...state.keepAliveList, pageName]
    }
  },
  DEL_KEEP_ALIVE_LIST: (state, pageName) => {
  // findIndex() 方法为数组中的每个元素都调用一次函数执行:
	//当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
	//如果没有符合条件的元素返回 -1
    if (state.keepAliveList.includes(pageName)) {
      const index = state.keepAliveList.findIndex(item => item === pageName)
      // const index = state.keepAliveList.findIndex(function (item) {
      //   if (item === pageName) {
      //     return item
      //   }
      // })
      state.keepAliveList.splice(index, 1)
    }
  }
}
export default {
  // commit、dispach的时候在触发的方法前加上该模块名,为了方便找到对应的文件。具体如下
  // this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', this.$options.name)
  // 如果namespaced: true,具体页面则可以按照上面
  namespaced: true,
  state,
  mutations
}

store/modules/keepAliveGetters.js

// 相当于计算属性
// 当keepAliveList,变化时,它会重新求值并且把结果缓存起来;如果没有变化,它会用之前缓存好的值
const getters = {
  keepAliveList: state => state.keepAlive.keepAliveList
  // keepAliveList: function(state) {
  //   return state.keepAlive.keepAliveList
  // }
};

export default getters

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import global from './global/'
//引入
import keepAlive from './modules/keepAlive.js'
import keepAliveGetters from './modules/keepAliveGetters'
Vue.use(Vuex)
export default new Vuex.Store({
    modules: {
    	global,
      	keepAlive
    },
    // 导出
    getters: keepAliveGetters
})

projList.vue

<template>
  // 使用滚动组件
  <scroller v-if="listView" lock-x class="scrollerBox" @on-scroll-bottom="onScrollBottom" ref="scrollerBottom" :scroll-bottom-offst="0" style="padding-bottom:0;">
    <div class="box">
    </div>
  </scroller>
</template>

<script>
export default {
  // 首先name唯一,keepAlive的是需要用到 / 递归组件的时候需要用到
  name: 'projList',
  data(){
    return{
      listView: true,
    }
  },
  // 通过这种方式,我们在导航转入新的路由前获取数据
  // beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。通过 `vm` 访问组件实例
  beforeRouteEnter(to, from, next) {
    next(vm => {
      vm.$store.commit('keepAlive/SET_KEEP_ALIVE_LIST', vm.$options.name)
    })
  },
  beforeRouteLeave(to, from, next) {
    if (to.path !== '/project/detail') {
      this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', this.$options.name)
    }
    next()
  },

  created () {},
  methods: {}
}
</script>

projDetail.vue

<template>
  <scroller lock-x style="padding-bottom:0;">
   <div>
   </div>
  </scroller>
</template>

export default {
  name: 'projDetail',
  data () {
    return {}
  },
  created () {},
  // 进入这个页面之前
  beforeRouteEnter(to, from, next) {
    next(vm => {
      vm.$store.commit('keepAlive/SET_KEEP_ALIVE_LIST', vm.$options.name)
    })
  },
  // 离开这个页面之前
  beforeRouteLeave(to, from, next) {
    const keys = ['/project/pay', '/project/contract', '/project/payment']
    if (!keys.includes(to.path)) {
      this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', this.$options.name)
    }
    next()
  },
  
}

参考文章:
vue 使用keep-alive缓存tab切换组件,保持每个组件滚动条位置
路由导航守卫beforeRouteEnter / beforeRouteLeave
keep-alive
在动态组件上使用 keep-alive
JavaScript findIndex() 方法
JavaScript splice() 方法

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐