Posted in

Apple 官网动画风格的实现_AI阅读总结 — 包阅AI

包阅导读总结

1. 关键词:Apple 官网动画、鼠标滚动、公式、节流算法、网页效果

2. 总结:作者喜欢 Apple 官网动画,在帮朋友做工厂官网时尝试实现类似效果。介绍了实现随鼠标滚动画线和元素依次出现效果的公式及思考过程,还提到在网页中的具体应用及通过节流算法优化性能和解决动画卡顿的方法。

3. 主要内容:

– 实现 Apple 风格网站动画的想法

– 作者喜欢 Apple 官网动画,借帮朋友做工厂官网的机会尝试实现类似效果

– 想实现的动画效果

– 随鼠标滚动画线以及元素依次出现

– 动画效果的精髓公式

– 介绍公式`let scrolled = html.scrollTop / (html.scrollHeight – html.clientHeight)`及思考过程

– 公式在网页中的具体应用

– 针对特定区域修改公式,实现网页滚动到展示动画所在元素时`scrolled`值增长

– 动画效果实现片段

– 包括画线和`li`元素依次出现的代码实现

– 节流算法优化性能和动画卡顿

– 介绍节流算法原理及在本案例中的使用和效果

思维导图:

文章地址:https://mp.weixin.qq.com/s/X7Rdqxg8mIf5mSBAezQ6lg

文章来源:mp.weixin.qq.com

作者:超级无敌攻城狮

发布时间:2024/8/16 3:18

语言:中文

总字数:2645字

预计阅读时间:11分钟

评分:85分

标签:网页动画,JavaScript,CSS,性能优化,滚动事件


以下为原文内容

本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com

点击公众关注号,“技术干货”及时达!

前言

本人非常喜欢Apple的官网动画,然后最近又正好在帮朋友做一个工厂的官网。借此机会做一个类似Apple风格的网站。

想实现的动画效果

想实现一个随着鼠标滚动画线以及元素依次出现的效果

精髓在于一条公式

Apple网站灵动的精髓在于有很多随鼠标滚动的动画。因此我们要处理的就是随着鼠标滚动的值与html元素之间的变化。

这条公式的作用是:随着鼠标滚动,页面从顶部到底部,scrolled会从0-1变化。

 let scrolled = html.scrollTop / (html.scrollHeight - html.clientHeight)

由于我是数学菜鸡,刚开始不太理解这条公式,后面想明白了。

分享一下我的思考过程

用到的API:

  1. html.scrollTop是html页面已经滚动的值
  2. html.scrollHeight是html页面的高度
  3. html.clientHeight是页面窗口的高度,也就是我们在浏览器看到的内容高度

当初的疑问

  1. html.scrollTop / (html.scrollHeight – html.clientHeight) :当滚动的像素等于页面高度的像素时,html.scrollTop / (html.scrollHeight – html.clientHeight)就等于1。
  2. 为什么要 (html.scrollHeight – html.clientHeight) ,页面滚动到底时,由于html.scrollHeight得到的是页面已经滚动的像素值,但这个值并不是页面到底的值,也就是说。此时html.scrollHeight与html.scrollHeight并不相等,相差一个视窗的高度像素值,所以需要减去视窗的高度。

在网页中的具体应用

由于并不是整个页面滚动,所以需要把公式由原来的滚动距离相较于整个页面高度改成相较于我们需要实现效果的区域

公式就变成了这样

 let parentElement = el.parentElement; //获取父元素
let htmlScrollTop = document.documentElement.scrollTop + document.documentElement.clientHeight// 页面已滚动的高度
let offsetTop = parentElement.offsetTop //元素顶部距离页面高度
if (htmlScrollTop >= offsetTop && htmlScrollTop <= offsetHeight) {
let scrolled = (htmlScrollTop - offsetTop) / (offsetHeight - offsetTop)
}

改动的地方:

  1. 将滚动高度改为滚动高度减去展示动画所在元素的高度(htmlScrollTop – offsetTop)

这样就能实现网页滚动到展示动画所在元素时scrolled值增长,滚动到元素底部时,为1。然后就可以随着值的改变通过dom改变元素了!

效果实现片段

需要注意的是这里是vue3的代码片段。

画线:通过设置长度值慢慢把线画出来el.style.height = ${scrolled * 90}%

li元素的依次出现:

计算每个元素应该出现的区间,然后通过设置 CSS 自定义属性来显示元素。

        let total = 1 / liElements.length
for (let index = 0; index < liElements.length; index++) {
let row = liElements[index]
let start = total * index
let end = total * (index + 1)
let progress = (scrolled - start) / (end - start)
if (progress >= 1) progress = 1
if (progress <= 0) progress = 0
row.style.setProperty('--progress', progress)
}

全部代码

html部分:

<div class="line" v-scrolling-line></div>
<li class="liLeft">
<h2>2000年</h2>
<h2>成立永发模具厂</h2>
<p>以小作坊形式开始运作</p>
<img src="src\assets\images\page2-1.jpg" alt="">
</li>
<li class="liRigth">
<h2>2006年</h2>
<h2>引进先进设备</h2>
<p>通过多次技改项目的投入,工厂
不断引进设备、人才、软件。</p>
<img src="src\assets\images\page2-2.jpg" alt="">
</li>
<li class="liLeft">
<h2>2016年</h2>
<h2>更名为天龙模具加工厂</h2>
<p>现为集产品和模具开发、设计、
制造于一体的科技型企业。</p>
<img src="src\assets\images\page2-3.jpg" alt="">
</li>

js部分:

const vScrollingLine = {
mounted: (el) => {
window.addEventListener('scroll', () => {

let parentElement = el.parentElement; //获取父元素
let htmlScrollTop = document.documentElement.scrollTop + document.documentElement.clientHeight// 已滚动高度
let offsetTop = parentElement.offsetTop //元素距离页面高度
let offsetHeight = offsetTop + parentElement.offsetHeight //元素底部距离页面高度,也就是顶部加上元素的高度。

let liElements = document.querySelectorAll('.page2>li')
if (htmlScrollTop >= offsetTop && htmlScrollTop <= offsetHeight) {
let scrolled = (htmlScrollTop - offsetTop) / (offsetHeight - offsetTop)
el.style.height = `${scrolled * 90}%`

let total = 1 / liElements.length
for (let index = 0; index < liElements.length; index++) {
let row = liElements[index]
let start = total * index
let end = total * (index + 1)
let progress = (scrolled - start) / (end - start)
if (progress >= 1) progress = 1
if (progress <= 0) progress = 0
row.style.setProperty('--progress', progress)
}
}

})
}
}

css部分:

  .line {
position: absolute;
left: 50%;
top: 0%;
transform: translateX(-50%);

width: 13px;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
background-color: white;
}

li {
list-style: none;
--progress: 0;
opacity: var(--progress);
img {
width: 30vw;
}

&.liLeft {
transform: scale(calc(1.8 - (0.8 * var(--progress)))) translateX(-80%) translateY(calc(-60px * (1 - var(--progress))));
}

&.liRigth {
transform: scale(calc(1.8 - (0.8 * var(--progress)))) translateX(80%) translateY(calc(-60px * (1 - var(--progress))));
}
}

附上自己在pad画的思考过程

9487e5a52d05e8d44b6c97b398239ef.jpg

通过节流算法优化性能和动画卡顿

什么是节流算法

节流的原理是,如果你频繁触发一个函数,那么在一段时间内只执行一次,不管这段时间内触发多少次。这种技术常用于滚动事件,比如滚动加载更多,滚动监听等场景。一个经典的节流算法:

functionthrottle(func,wait){
letlastTime=0;
returnfunction(){
letnow=Date.now();
if(now-lastTime>wait){
func();
lastTime=now;
}
}
}

具体到本案例中的使用:

这段代码实现了通过节流算法,哪怕在有效范围内触发了滚动监视器,其中的回调函数也并不会一直执行,会保持17毫秒的间隔,理论上这里通过数值越小动画越流畅,但是由于对DOM的操作会消耗大量的性能,实际上反而会造成卡顿,而人眼能感知的最高帧率大约是60帧/秒,也就是每帧大约16.67毫秒。JavaScript无法处理带小数点的毫秒,所以四舍五入设置为了17

functionthorttle(func,waitTime){
letstartTime=0
returnfunction(){
letnow=Date.now()
if(now-startTime>=waitTime){
func.apply(this,arguments)
startTime=now
}
}
}

letpageScroll=(el)=>{
returnfunction(){
letparentElement=el.parentElement;//获取父元素
lethtmlScrollTop=document.documentElement.scrollTop+document.documentElement.clientHeight//已滚动高度
letoffsetTop=parentElement.offsetTop//元素距离页面高度
letoffsetHeight=offsetTop+parentElement.offsetHeight//元素底部距离页面高度,也就是顶部加上元素的高度。

letliElements=document.querySelectorAll('.page2>li')
if(htmlScrollTop>=offsetTop&&htmlScrollTop<=offsetHeight){
letscrolled=(htmlScrollTop-offsetTop)/(offsetHeight-offsetTop)
el.style.height=`${scrolled*90}%`
lettotal=1/liElements.length
for(letindex=0;index<liElements.length;index++){
letrow=liElements[index]
letstart=total*index
letend=total*(index+1)
letprogress=(scrolled-start)/(end-start)
if(progress>=1)progress=1
if(progress<=0)progress=0
row.style.setProperty('--progress',progress)
}
}
}
}


constvScrollingLine={
mounted:(el)=>{
window.addEventListener('scroll',thorttle(pageScroll(el),17))
}
}