受苹果网页动画的启发,我写了一个JS库

4,933 阅读4分钟

大家好,我是 Steven。

我喜欢苹果的产品,也喜欢他们的网站。他们在网页中做了很多很棒的动画效果来介绍产品,大部分都是基于页面滚动的,当我们上下滚动网页时,动画会向前和向后播放。

作为一名前端开发者,我常常试着重现他们的动画来学习,并将其录制为教学视频。

而要实现基于页面滚动的动画,必须使用 JavaScript 做一些计算,比如元素是否出现在屏幕上、滚动的距离、元素偏移量等等,然后相应地更新元素的样式。

由于实现这类动画都有着以上提到的共通点,我在想能否把开发过程变得更简单,比如说,不用编写一行 JavaScript 就可以实现这类动画。

初始想法

基于页面滚动的动画效果,主要关乎到滚动的距离以及元素的位置。元素从页面底部出现到从顶部消失,我希望通过一个数字来表达,从 01 就很适合,至少就目前来说。

然后使用 IntersectionObserver API 来监听元素是否出现在屏幕当中。接下来,就要考虑用什么方式来使用这个数字。

灵活性

由于动画千变万化,例如元素的淡入淡出、元素的移动、改变文本的颜色等等,而且不仅于此。所以我们需要一个足够灵活的方式来调整样式,CSS 变量就是一个很好的选择。

库的名称

我将这个库命名为 Trigger JS,Trigger 的意思是触发。因为每次滚动都会触发一个新的值,纯碎是字面意思。

对 JavaScript 使用的思考

这个库的目标是让开发者在无需编写 JavaScript 的情况下,即可建立基于页面滚动的动画。所以,我决定通过 HTML 属性和 CSS 变量来实现。

由于库名是 Trigger JS,所以我使用了 tg- 作为相关 HTML 属性的前缀。我知道 tg- 可能不太符合 HTML5 的标准,没关系,我会保留一个选项来自定义前缀,例如data-tg-*,彻底摆脱这个顾虑。而本文将继续使用 tg- 来讲解。

第一个属性:tg-name

tg-name 属性主要有两个用途:定义需要监控的元素和 CSS 变量的名称。

tg-name 属性添加到需要监控的元素中,例如:

<h1 tg-name="opacity">
  Hello World
</h1>

Trigger JS 会将所有带有 tg-name 属性的 HTML 元素获取到一个名为 activeElements 的数组中(通过 document.querySelector('[tg-name'])),并使用 IntersectionObserver API 来监听它们的出现。

增加一个 scroll 事件监听器到 window,计算 activeElements 中元素相对与屏幕的位置:元素从底部出现时为 0,从顶部消失时为 1,在中间时为 0.5

最后,我们将这个计算结果通过 CSS 变量设定到指定的元素中,例如 --opacity: 0.5。这样我们就可以在相应的 CSS 属性中应用该值,在本例中,就是 opacity: var(--opacity);

设置数值范围

01 这个数字,在某些情况下很好。但是如果我们想通过 transform 来移动一个元素,调整数值的起始和结束值就会变得更为方便(尽管可以在 CSS 中通过 calc() 来计算)。

这就是为什么我添加了 tg-fromtg-to。如果想在页面向上滚动时,将元素由右往左移动 400px,可以设置 tg-from="200"tg-to="-200"

对了,还需要定义间距,设置为 tg-steps="400" 就等于每次移动 1px。但是如果我们更改了 tg-fromtg-to,又想保持每一次递增 1px 的话,可以使用另一个属性 tg-step="1",这样就不用自行计算了。

数字并不完美

有时,我们需要一个特定的值。假设我们要更改文本颜色,需要的是颜色代码而不是数字。这就是添加 tg-map 属性的原因,使我们能够将值从数字转换为特定的值。

例如:

<h1
  tg-name="color"
  tg-from="0"
  tg-to="2"
  tg-step="1"
  tg-map="0: black; 1: blue; 2: purple"
>
  Hello World
<h1>

在整个滚动过程中,计算值将是 012。然后使用 tg-map 中的设置转换为最终值:

  • 0 -> black
  • 1 -> blue
  • 2 -> purple

因此,我们可以使用以下方式轻松更新文本颜色:

<style>
h1 {
  color: var(--color);
}
</style>

降噪

有时我们只对某些特定的值感兴趣。例如,我们只想知道从 0100 (tg-from="0" 以及 tg-to="100") 之间,什么时候出现 25, 50, 75。在这个情况中,tg-filter 就可以帮上忙。

<h1
  id="heading"
  tg-name="color"
  tg-from="0"
  tg-to="100"
  tg-step="1"
  tg-filter="25,50,75"
  tg-map="25: red; 50: yellow; 75: green"
>
  Red (25), Yellow (50), Green (75)
</h1>

<style>
  body {
    padding: 100vh 0; /* In order to make the page have enough rooms for scrolling */
  }

  #heading {
    color: var(--color);
  }
</style>

开源

以上是创建这个 JS 库的原因以及想法,目前 Trigger JS 已开源,可以在 GitHub-triggerjs/trigger 找到。

欢迎您测试它,提交 PR 请求并分享您的想法,您的意见对于 Trigger JS 的发展非常宝贵。

如果您喜欢它,请给它一个 Star。如果能有您的参与就更好了!

一起加油!