Vue的keep-alive|Vue的keep-alive 实现滑动定位缓存

Situation
首先该项目是一个h5项目,有一个滑动列表页,当我滑动点击列表项,会进入到详情页,当我退出的时候,我希望还能定位到我刚刚点进来的位置。
【Vue的keep-alive|Vue的keep-alive 实现滑动定位缓存】Task
我们的目的是定位滑动位置。在返回的时候应该回到刚刚的滑动位置。
所以我们有两个关键点,第一个是怎么定位滑动位置,第二是返回的时候怎么回到滑动位置。滑动位置的话我们可以获取到滑动容器的scrollTop值,然后返回的时候设置滑动容器的scrollTop就可以定位。
Action
1. 采用scrollBehavior 函数

使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
const router = new VueRouter({ routes: [...], scrollBehavior (to, from, savedPosition) { // return 期望滚动到哪个的位置 } })

scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。
所以在定义router的地方,挂载了scrollBehavior函数。
  • 问题:savedPosition打印出来的x,y坐标,不是想要的,不准确。
  • 分析:因为scrollBehavior是挂载在路由身上,它对应的应该是一个整个路由组件,而我的滑动区域是组件里面的一个固定区域,也就是说,我应该把scrollTop挂在滑动区域,但是整个页面结构不允许我这样做。所以尝试第二种方法,keep-alive
2. keep-alive
Keep-alive 是什么?这可不是http保持长链接的keep-alive哦
keepalive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存
但是有个问题是,它不会缓存我们的滑动位置,我们需要手动记录位置。
a. 在滑动的时候记录滑动组件的scrollTop (这里可以加一个节流函数)
onScroll(e: Event) { const { scrollTop } = e.target as HTMLElement; this.scrollTop = scrollTop; // 记录滑动位置,回来时恢复到此位置 }

keep-alive的声明周期执行
  • 页面第一次进入,钩子的触发顺序:
    created-> mounted-> activated,
    退出时触发 deactivated 当再次进入(前进或者后退)时,只触发 activated
  • 事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中;
b. 所以我们在activated声明周期中定位我们的位置
activated() { // 恢复之前保存的位置 (this.$refs.scroller as HTMLElement).scrollTop = this.scrollTop; }

Result
被keepalive包含的组件不会被再次初始化,也就意味着不会重走生命周期函数。但是我们可以通过
activated, deactivated 两个生命周期进行控制。而且也避免了重新加载数据。
思考:
因为之前的技术栈是react,所以每次我写vue的时候都会下意识思考如果是用react我会怎么去实现。
  • 在 React 中,我们通常会使用路由去管理不同的页面,而在切换页面时,路由将会卸载掉未匹配的页面组件,所以上述列表页例子中,当用户从详情页退回列表页时,会回到列表页顶部,因为列表页组件被路由卸载后重建了,状态被丢失。
  • 如果说按照之前的做法,我可能是onScroll事件监听滑动,或者是点击列表项的时候获取到容器的scrollTop,然后把scrollTop存到我们model里面,并且需要判断路由状态,如果是从详情页跳转的,则需要读取scrollTop,在componentDidMount中定位,如果是从其他页面,比如首页进入到列表页,就不需要重新定位

    推荐阅读