Situation
首先该我的项目是一个 h5 我的项目,有一个滑动列表页,当我滑动点击列表项,会进入到详情页,当我退出的时候,我心愿还能定位到我刚刚点进来的地位。
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 中定位,如果是从其余页面,比方首页进入到列表页,就不须要从新定位