叮~来查收这份不一样的年度总结报告吧(掘金2022创作者版)
前言
年底相信大家都被各种年度总结报告刷屏了吧,看了那么多年度报告,都是一屏滑过一屏,动画全是清一色淡入加淡出,难免有些审美疲劳。
我在上一篇文章 2022年终总结 的时候临时起意,于是想设计出一个交互式年度总结网页,本想为平淡的这年增添亿点别样色彩,遗憾没能抓住2022的尾巴,此番就作为回顾的篇章与你一同分享吧!新年伊始,也不算晚~
食用指南
输入你或他人掘金ID (主页URL末尾数字),点击按钮等弹窗消失后上下滑动页面即可查看报告,推荐点击上方自动播放效果会更好。
-
请在 PC 端查看,移动端没做适配,头发能省几根是几根啊!需要保持横屏的比例效果较好。
-
如何发弹幕 --> 报告结束时会开启弹幕,在本文中的评论会自动更新到网页的弹幕列表中,重要的事情我只说一遍~( ゚∀゚) ノ♡
如果2022年整一年都没发过文章,你输入id后就没反应了( ´・・)ノ(._.`),所以标题才说是创作者版~你可以输入任意你在掘金喜欢的大佬id查看😍
ok,这两天开发的玩具到这里就介绍完毕了,没人看我也要写,因为主要我自己想玩!
但作为干货区作者(自封),下面就继续展开讲讲这个交互页面的主要实现要点。
吸附滚动原理
曾经,有一位伟岸的UI设计师跟我说过:
当时没文化的我只能说雀食牛逼啊朋友们,苹果官网的产品页那个炫啊,稚嫩的我在短暂体验过后心中就种下了一枚名为 滚动 的种子,虽然我做不出那么烧的效果,但也涌现出了不少灵感。
正如开头提到的,大多数网页报告交互手段都是点击切换到下一屏,然后用户就只能呆呆看着动画执行完毕才能又继续一下屏。
所以如果把每一屏的动画过程通过滚动方式交给用户去完成,是不是会更有意思一点呢!
我的设计思路很简单,把实际高度远超过屏幕高度的元素堆栈排放,每一屏的内容实际上要滑动一段距离才能到达底部,此时只需要让这个元素吸附在屏幕上就可以了,等到内容滑动到底了再解除吸附。
如何判断正在滑动的是哪一屏呢?so easy,每个元素都可以获取到 offsetTop
,这就是起始位置,每一屏的高度由我们自定义,结束位置也知道了(假设高度为h
,结束位置则为offsetTop
+h
),通过给 scroll
添加事件监听,在监听中获取到滚动距离(如:body.scrollTop
),这样当滚动距离大于某元素起始位置小于结束位置时,就是在这个元素中活动。
我们把这样一个元素先称呼为“盒子”吧,在每个盒子当中的滑动进度也很容易计算出来了:
progress = (scroll - startIndex) / (endIndex - startIndex)
利用每个盒子在滑动过程中产生的 progress
来控制盒子中的动画展示从 0%
到 100%
的过程,动画的节奏则由每一屏的高度决定,这就是我整个网页交互的核心。
现在问题只剩下如何实现吸附,这还不简单嘛,不就是绝对定位 absolute
或者 fixed
咯?
虽然这些都可以实现,但我觉得还得是 position: sticky
更加合适,它的使用场景可能有点少,而且曾经连谷歌浏览器都放弃了对它的支持,因此大概比较少人关注吧,但是现在看来完全不用担心兼容性啊,一眼望去那是比青青草原还要更加生机盎然:
那么这个 position: sticky
是个什么东西呢?翻译成人话讲就是 “粘性定位”,它可以看做是相对定位与绝对定位的结合体,但本身是属于流定位的,也就是和 relative
一样,不同的是它接受top right bottom left
等值的时候可以基于最近的祖先元素进行定位并牢牢地“粘”在窗口上,这种特性就使得我们很容易实现上述的效果。
我们把每一屏页面都设置为 position: sticky
而不设置偏移时,由于是流定位,此时不会形成堆叠上下文,它看起来就和 relative
没什么区别:
而当我们展示到某一页的时候,就把它设置为 top: 0
顶到页面中粘住,要注意此时它看起来虽然和绝对定位一样,但是却并没有脱离文档!我们直接就可以用这个元素把父级撑开,sticky
——专为滚动而生~ヽ(゚∀゚*)ノ━━━ゥ♪
现在可以开始咱们的表演了,赶紧掏出我心爱的 Vue3 + Vite 就是一顿疯狂操作 (ノ*・ω・)ノ
实现效果如下所示:
另外我也是把这个基础组件发布到了npm,如果你也想玩玩可以自取:
npm install @palxp/scroll-wrap-vue3
在线演示和 API 文档我就放在这里了 (* ̄3 ̄)╭ scroll-wrap-vue3 组件文档
Vue父子组件通信
在这个核心组件中,数据流向主要是父传子,所以通信方式采用插槽最为合适,我们的目的是将滚动层的进度传递到子组件中,在 ScrollWrap
中默认插槽传入数据:
<slot :progress="process"></slot>
调用时在父组件上通过 v-slot
取出 props
对象,就可以拿到传递的动态响应参数了,接下来就是传入子组件的 props
中控制动画,页面中部分代码展示如下:
<ScrollWrap v-slot="props" :long="wh">
<Text :value="'你好,' + user.name" :progress="props.progress" />
</ScrollWrap>
<ScrollWrap v-slot="props" :long="1.2 * wh">
<Text value="时光飞逝,一弹指顷" :destroy="true" :progress="props.progress" />
</ScrollWrap>
<ScrollWrap v-slot="props" :long="wh * 2">
<Text value="请查收你的专属回忆🌹" :destroy="true" :progress="props.progress" />
<Hello :progress="props.progress" />
</ScrollWrap>
插槽内的子组件都是些动画部分的代码,大部分成熟的动画库都有 timeline
功能,以 animejs 为例:
最后
完整项目开源地址:github.com/palxiao/jue…
猫喜欢吃鱼,却不能下水,鱼喜欢吃蚯蚓,却不能上岸。人生也是一边拥有,一边失去;一边选择,一边放弃。
不知不觉就过了这一年,偶尔停下,跟自己说两句话,第一句:看下吧,毕竟一年过去了;第二句:忘了吧,前面还有路呢。
以上就是文章的全部内容,感谢看到这里!本人知识水平有限,如有错误望不吝指正,如果觉得写得不错,对你有所帮助或启发,可以点赞收藏支持一下,也欢迎关注,我会更新更多实用的前端知识与技巧。我是茶无味de一天,希望与你共同成长~