Vue3 + Pinia 仿抖音,Vue 在移动端的最佳实践
John DoeVue3 + Pinia 仿抖音,Vue 在移动端的最佳实践
zyronon/douyin: Vue3 + Pinia 仿抖音,Vue 在移动端的最佳实践 . Imitate TikTok ,Vue Best practices on Mobile (github.com)
页面跳转的动画
在App.vue 里面有监听路由的路径,通过判断路由定义的顺序来判断路由是前进还是后退, 然后添加对应的动画。
1 2 3
| <transition :name="transitionName"> // 这里修改动画名 </transition>
|
路由过渡的时候会出现白屏
这是由于每个页面都是 block 元素。使用动画过渡的时候, 上一个页面和下一个页面都是 block 元素。默认的文档流是垂直排列。 所以下一个元素会排列在上一个元素的下面。
解决办法就是将页面元素作为非 block 元素。 一般的防暑是页面根元素脱离文档流, 利用absolute 或者 fixed 等。我比较倾向于在 router-view 外面套一层 flex 元素。 这样子页面就不用每个去添加样式了。 该软件的作者也写了一篇文章来说明过渡动画应该怎么使用Vue 路由使用介绍以及添加转场动画 - 掘金 (juejin.cn)
如何判断路由是前进还是后退
该软件的作者是通过路由的定义顺序进行判断的。 这种方式有一定的局限性
⬇️作者方案
1 2 3
| const toDepth = routes.findIndex((v: RouteRecordRaw) => v.path === to) const fromDepth = routes.findIndex((v: RouteRecordRaw) => v.path === from) transitionName.value = toDepth > fromDepth ? 'go' : 'back'
|
⬇️利用 window.history.state 控制
vue3 路由判断是前进还是后退_vue3 路由守卫判断是否回退-CSDN博客
vue-router@4、history.state和标记第一层路由的方法 - 掘金 (juejin.cn)
动画
消息页左侧的加号
用了一个自定义组件 FromBottomDialog 这个组件通过监听 modelValue 来控制显隐。这里有点没看懂。 页面都是固定的屏幕高度, 为什么还要处理 body 的 scroll。代码的注意内容是当 modelValue 为true 的时候, 手动创建一个遮罩层(添加 fade-in 动画。 0.3秒的透明度变化)。modelValue为 false 的时候, 又重新创建了一个 mask的自定义 Dom 类实例,然后隐藏这个 mask, 添加fade-out 样式类名。弹窗的动画是用了一个 transtion。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| watch( () => props.modelValue, (newVal: boolean) => { const page = document.getElementById(props.pageId) if (!page) return if (newVal) { pagePosition.value = _css(page, 'position') page.style.position = 'absolute' scroll.value = document.documentElement.scrollTop document.body.style.position = 'fixed' document.body.style.top = -scroll.value + 'px'
const maskTemplate = `<div class="Mask fade-in ${props.maskMode}"></div>` const mask = new Dom().create(maskTemplate) setTimeout(() => { mask.on('click', (e: Event) => { _stopPropagation(e) onHide() }) }, 200) page.appendChild(mask.els[0]) } else { page.style.position = pagePosition.value || 'fixed' document.body.style.position = 'static' document.documentElement.scrollTop = scroll.value
const mask = new Dom('.Mask').replaceClass('fade-in', 'fade-out') setTimeout(() => { mask.remove() }, 250) } } )
|
loading 小球动画
文件是 Loading.vue
两个块元素,scale 和 transform 左右交替
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| .blue { background: cadetblue; animation: anim-blue 0.4s ease-in-out 0s infinite alternate; }
.red { background: var(--primary-btn-color); animation: anim-red 0.4s ease-in-out 0s infinite alternate; }
@keyframes anim-blue { from { transform: translate3d(0, 0, 0) scale(1); } to { transform: translate3d(10rem, 0, 0) scale(1.2); } } @keyframes anim-red { from { transform: translate3d(0, 0, 0) scale(1); } to { transform: translate3d(-10rem, 0, 0) scale(1.2); } }
|
我的下面下拉上滑动画
Screen-2024-05-22-231355.mp4
- 下拉的时候背景图片会变大
- 监听touch 事件。修改背景图片的高度。由于图片设置了cover。 高度修改的时候,就会产生图片变大的效果.松开手后, 给元素添加动画时长。然后背景图片高度复原
- 上滑的时候顶部菜单会变黑。
Math.abs(pageMoveDistance) > 100的时候将变量改变, 修改对应的样式
评论弹窗高度变化时 video 高度变化
用了 eventbus 通讯
Screen-2024-05-22-235658.mp4
post 详情的动画
点击文章路由不跳转但是文章全屏
Screen-2024-05-23-221450.mp4
首先复制元素到’.shadow.wrap’. 这个元素作为 d。缩略图元素 opcatity 由1到0,详情元素由0到1. z-index 也变, 产生了动画效果。这里都是通过_css 操作的
其他
弹窗滑动到顶部继续滑动关闭弹窗
判断是否滑动到顶部用 wrapper.value?.scrollTop !== 0