前端实现苹果官网 的滚动动画 时间轴动画、序列动画实现解析

编程入门 行业动态 更新时间:2024-10-10 05:16:06

前端实现苹果官网 的滚动<a href=https://www.elefans.com/category/jswz/34/1769013.html style=动画 时间轴动画、序列动画实现解析"/>

前端实现苹果官网 的滚动动画 时间轴动画、序列动画实现解析

苹果的官网一直是引领者前端网页效果的发展,本文对苹果mac book的宣传页面前端实现做一个实现步骤的解析和复现  使用框架   react   ts

首先看原网页效果:

苹果macair网页效果

首先观察页面,随着页面滚动,开头一个标题文字逐渐放大,放到最大之后标题消失然后出现笔记本的元素随着滚动逐渐打开,然后出现笔记本文字,注意: 这些元素没有随着滚动而往下动,而是吸顶定位,ok  现在页面大概方式大概理完了,开始下一步

笔记本和标题为什么滚动的时候没有跟着滚动?

直接讲实现方式吧,   position: sticky;   top:0    粘性布局,  最外层的总div设置的非常高,比如800vh  ,就是八个屏幕的高度,内部的元素都堆叠在一起控制显示和隐藏,然后内部的这些元素的小div就是大概100vh的高度   设置粘性布局,top:0,这个时候就发现滚动的时候里边的div就固定在中间了,等大div  800vh滚动结束的时候内部div才会随着滚动,这个时候发现整体的布局就结束了,进行下一步 , 操作元素的显示隐藏等动画时间轴

操作元素的时间轴动画

上一步已经布局好了,假设布局中共计三个子元素,包含一个h1标题,一个笔记本元素,一个笔记本名称,这三个元素需要在不同的滚动节点出现,并可以设置不同的样式,并且随着滚动的距离控制动画的进度,并且支持回滚等操作,一听这就是十分复杂的,其中笔记本还随着滚动有开合的效果,先告诉大家笔记本是怎么实现的

笔记本随滚动的开合效果:  笔记本是个视频,滚动的时候根据滚动距离设置视频的当前帧时间定位,属性是  currentTime  ,操作方式就是   dom.currentTime = *  就行

那现在开始思考如何让这三个元素紧密衔接进行动画操作?假设整个div的800vw是个时间轴 共计100%,那么监控这个div距离顶部的距离就可以得到滚动了多少尺寸,通过比值计算就可以得到滚动的百分比,得到当前滚动到了百分之多少的位置,假设提前定义好了不同的百分比距离的样式,那么根据这个就可以计算该设置的样式了,先看一张图

 红色圈起来的就是我的组件的配置项,我定义了三个元素的不同节点的时候该展示什么样的样式,专业叫法叫关键帧,比如像h1,滚动到0%的时候我定义透明度 0.1,大小 1倍,滚动到15%的时候透明度1,大小一倍,讲到这里可能你稍微有了一点想法,我把元素的变化的关键帧都配置好,通过id(有点low用id)去进行关联元素,这样的话我再拿到当前滚动的百分比,我就可以判断当前滚动到了那个关键帧,假设滚动到了   9%,那么我就循环所有的配置项,一个一个的找到元素9%的时候该是什么样式,比如h1元素,就是在   0% 关键帧到 15%关键帧之间,这里有点复杂需要理解下,就是获取到两个前后关键帧才能计算他们的样式该是什么,下文成为前后帧,9%  在1  到  15 这俩前后帧中处在  60%(这里怎么计算需要自己感悟,9 / 15 / 100 = 60 %),百分之60再计算前后帧之间样式的差,比如 0帧的时候透明度 0.1   15关键帧透明度1,那么前后帧的透明度差就是0.9  再  * 计算出的所处位置  60%  就等于 0.54 透明度,然后根据id修改元素的样式就行了,这里的计算方法是核心复杂点,需要好好理解消化,计算方法已经写成了通用的组件,可以看下文

总结

看的云里雾里的,再总结梳理一下,定义好时间轴配置,每个元素到哪个节点该干什么,然后求div滚动的百分比得到滚动到哪了,然后根据滚动到的位置百分比得值去求时间轴配置里边找关键帧,然后找到前后关键帧之后计算该设置什么样式,设置样式就行了,看不懂的话就直接拿下边代码直接用吧,react 函数式写法,ts,支持常见样式变化

最终通用组件代码

import React, {  cloneElement, useEffect, useRef, useState } from "react"
import './index.less'
import { isBrowser } from "@utils/util"export default ({children, config,  ...rest}:any)=> {const [refList, setRefList] = useState({})const { props } = children || {}const { children:childrenList, ref, ...rest1 } = props || {}const allRef = ref ? ref : useRef(null) as anyconst timeRef = useRef(null)//   6,在这里计算前后帧和滚动百分比,得到该设置的值const handleStyle = (dom: HTMLElement | null, endStyle: any, beginStyle: any, value: number)=> {const endStyleList = Object.keys(endStyle) as anyendStyleList.forEach((key:any , index: number)=> {const itemStyle = endStyle[key]if(key === 'scale'){dom.style.transform = `scale(${(endStyle[key] - beginStyle[key])*value / 100 + beginStyle[key]})`} else if(key === 'top'){dom.style.transform = `translateY(${(endStyle[key] - beginStyle[key])*value / 100}px)`}  else if(key === 'currentTime'){requestAnimationFrame(()=> dom[key] = `${(endStyle[key] - beginStyle[key])*value / 100 || value}`)} else {dom.style[key] = `${(endStyle[key] - beginStyle[key]) * value / 100 + beginStyle[key]}`}});}const handleScroll = () => {// 2, 计算出接收的组件的位置高度距离信息// 动画容器距离网页顶部的滚动距离const { top } = allRef.current.parentNode.getBoundingClientRect() || {top: 0}// 网页可视高度const viewHeight = document.body.clientHeight// 动画容器的高度  + 0.5页面高度为了优化结束的时候的效果const all_height = isBrowser() ? allRef.current?.parentNode.scrollHeight + 0.5 * viewHeight: 1200   //页面显示区域总高度// 计算动画容器距离底部网上滚动的多少const top_value = -top + viewHeight// 根据动画元素容器滚动的距离计算出已经滚动距离的百分比let proportion = 100 - (all_height - top_value)/all_height * 100const proportionValue = proportion <= 0 ? 0 : (proportion >= 100 ? 100 : proportion)// 3,遍历接收的子节点,有配置时间轴的话就去做动画处理childrenList.forEach((element:any) => {const { id } = element.propslet configList = config[id]let dom = document.getElementById(id)if(configList){const config = Object.keys(configList) as anyfor (let index = 0; index < config.length; index++) {const key = config[index];const lastKey = config[(index === 0 || (index === config.length-1 && proportionValue >= config[index])) ? index : index - 1 ]if( Number(key) >= proportionValue || index === config.length -1){// // 4, 计算当前阶段走到的比例值const now_value = key === lastKey ? 100 : (1 - (key - proportionValue) / (key - lastKey)) * 100//  requestAnimationFrame(()=> handleStyle(dom, configList[key], configList[lastKey], now_value ))// 5, 定义的设置dom样式的方法,传进去dom  前后帧,当前的滚动位置百分比handleStyle(dom, configList[key], configList[lastKey], now_value )break }}} else {return } });}useEffect(()=> {// 1 , 设置滚动监听事件   约17毫秒一次,handleScroll()isBrowser() &&  window.addEventListener('scroll', handleScroll);return (()=> {isBrowser() &&  window.removeEventListener('scroll', handleScroll)})}, [])return <div {...rest1} ref={allRef}>{childrenList.map((element: any, index: number) => {const { className, style, ...rest } = element.propsreturn  cloneElement(element,{...element.props, className: className, } )})}</div> 
}

使用方法

<div className="test223"><RollAnimationconfig={{title: {0: {opacity: 0.1,scale:1 },15: {opacity: 1,scale:1},40: {opacity: 1,scale:260},45: {opacity: 1,scale:340},50:{opacity: 1,scale:580.5},51:{opacity: 0,scale:595},},video: {0: {opacity: 0, currentTime:0},50:{opacity: 0,currentTime:2.5},51:{opacity: 1,currentTime:2.52},100:{opacity: 1, currentTime:5.5},},span1: {49:{scale:0, opacity: 0,},65: {scale:1 , opacity: 0,},72: {scale:1, opacity: 1,},80 : {scale:1, opacity: 0,},},}}><div className="video"><h1 id="title" className="test">华为云服务</h1><div id="span1">啊</div><video  id="video" ref={myVideo} src={'.webm'} ></video></div></RollAnimation></div>

注意最外层div设置的要高一点,内部div定位方式要设置一下,拿过去就可以直接  react使用,效果基本还原一致,在动画框架中还没看到相似功能的,代码比较烂,仅供参考

更多推荐

前端实现苹果官网 的滚动动画 时间轴动画、序列动画实现解析

本文发布于:2024-02-13 17:08:57,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1759411.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:动画   序列   官网   苹果   时间

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!