Appearance
仿今日头条翻页动画及保持滚动位置
适用范围
目前只适用于 Vue.js 2 项目,如果要应用到 Vue.js 3 可能要有少量修改,请自行修改。
技术目标
模仿《今日头条》APP 页面进出场动画,即:凡是 Z 轴靠下的页面保持不动,凡是 Z 轴靠上的页面要实现动画,多个页面好似一叠纸摞在一起,可以放上新纸或抽走最顶层的纸。
如果 A 页面已经在历史中,而 B 页面有链接可跳转到 A 页面,此时跳转的话,必须实现回退动画而不是前进动画。
不动的页面必须使用
position: static
定位,避免脱离正常流导致额外系统开销。如同《今日头条》,已访问过的页面的滚动条位置要能够自动记忆,当前进、回退时均可自动滚动到记忆位置。
要能够自由设定某页面路由到另一某页面时,滚动到记忆位置或不滚动到记忆位置。
保持滚动条位置与 keep-alive 无关,不缓存的页面也必须支持记忆滚动条位置。
关于着陆页的特别要求:实践中,Webview 的着陆页有可能不是首页,这时路由事实上是从首页跳转到着陆页,虽然有跳转,但此时不允许出现翻页动画。
DEMO
源码
实现原理
见上方源码中 App.vue、router/index.js、store/index.js 的代码和注释,尤其是 App.vue 的 mixins 和 SCSS 文件的注释。
测试办法
打开上方 DEMO 链接,测试流程见上方 DEMO 各个页面中的文字介绍。
部署方法
现在假设你已经有一个新建项目或老项目。
拷贝文件或照抄代码
仿照本项目,在你项目的 App.vue 中引入一个 mixins 和一个 SCSS 文件,你可以自由修改文件内容,因为注释很清晰。
仿照本项目,你项目的 router/index.js 中必须给所有页面加上
name
字段,且必须给所有 TabBar 级别页面加上meta: {isTabBar: true}
。你项目的 store/index.js 中必须照抄本项目的 2 个 state 和 2 个 mutations,具体看本项目源码。
本项目的 components/NavBar.vue 实现了 Webview 自下级页面着陆后,点击回退按钮则关闭页面。你可以照抄或仿照源码。
搭建页面
非 TabBar 级页面必须使用一个且只能使用一个
div.normal-container
容器包裹所有非 fixed 的内容,且它必须是页面最外层<div />
的直接子元素。由于 TabBar 级页面不可能有动画,所以 TabBar 级页面不需要使用这个 class。非 TabBar 级页面必须给所有 fixed 元素本身(必须是本身,不得是父元素)分别加上
.fixed-container
,且每个 fixed 元素的宽度必须是视口宽度,如果实在无法做到,最好先引导用户关闭 fixed 元素,或者自动关闭 fixed 元素。本项目使用了 Vant 组件库的 NavBar、TabBar、Search 组件,你可以参考相关代码。
使用标记保持滚动位置
凡希望新页面保持滚动位置,要给params
传入keepScrollY: true
,例如:
js
this.$router.push({ name: 'Article', query: { id: 2 }, params: { keepScrollY: true } });
注意事项
保持滚动位置前提是页面高度保持不变
道理很显然,页面高度如果是变化的,那么滚动位置有可能是不准的,所以:要么页面内容全是静态的,要么锁定每块区块的高度,要么需要使用 keep-alive 缓存内容,否则保持滚动位置就没有意义。由于使用 keep-alive 技术很简单,本项目不再演示,你可以参考《Vue.js 开发最佳实践 - Vue-Router》。
注意:App.vue 的<transition />
应写在<keep-alive />
的外层。
关于 z-index
页面切换和复杂的页面布局都避不开z-index
层级,为使问题最简单化,请你遵守:
竭力避免使用
z-index
。当出现意外的层级顺序时,应最优先考虑调整代码书写顺序,将 Z 轴更靠上的组件写在代码更靠下方,而不是使用z-index
粗暴调整层级,因为给某个元素加z-index
可能会引起层级混乱,导致一系列连锁反应,类似于“你用谎言掩盖谎言,最后得到的只能是更大的谎言”,所以,比如页面顶部固定浮动的组件,虽然位置在页面最上方,但代码要写在正常流内容的下方。Vant 组件库的 Tabbar 组件的默认
z-index
是1
,请重置为auto
,否则也会引起一系列麻烦。本 DEMO 已实施此修改。
与《仿微信...》方案的区别
微信翻页动画是新旧页面都有动画,今日头条翻页动画是只有其中一个页面有动画,今日头条的动画更省资源,卡顿概率更低。
微信动画既然涉及两个页面,那么 TabBar 级页面也必须使用
div.normal-container
和.fixed-container
,而今日头条的 TabBar 级页面永远不会有动画,所以没限制。
如何切换到《仿微信...》方案
替换 App.vue 中引入的 SCSS 文件,也就是使用《仿微信翻页动画及保持滚动位置》源码中的对应 SCSS 文件。
仿微信项目的 TabBar 级页面也必须使用
div.normal-container
和.fixed-container
。