本文最后更新于 2 年前,文中所描述的信息可能已发生改变。
概述
渡一短视频–钉钉官网动效demo
- 动画状态函数
- sticky布局
钉钉官网动效简易实现
渡一短视频–钉钉官网动效demo
效果
代码分析
布局
html
<div class="header">page header</div>
<div class="ground-box">
<div class="animate-box">
<div class="list">
<div class="con"></div>
<div data-order="0" class="item"></div>
<div data-order="1" class="item"></div>
<div data-order="2" class="item"></div>
<div data-order="3" class="item"></div>
<div data-order="2" class="item"></div>
<div data-order="1" class="item"></div>
<div data-order="0" class="item"></div>
<div data-order="0" class="item"></div>
<div data-order="1" class="item"></div>
<div data-order="2" class="item"></div>
<div data-order="3" class="item"></div>
<div data-order="2" class="item"></div>
<div data-order="1" class="item"></div>
<div data-order="0" class="item"></div>
</div>
</div>
</div>
<div class="footer">page footer</div>
list
为动画的主要部分,动画随着鼠标的滚动开始和结束。可以看到在页面滚动时,动画部分是固定在视口区的。可以布局如下:
list
使用position: sticky 布局- 让
animate-box
的高度高一些
animate-box
作为list
第一个父级可滚动元素,list会固定在视口区,直到父盒子离开视口,随着父盒子一起离开视。
js动画
动画的过程为:(开始位置,开始状态)->(结束位置,结束状态),实际上是一个一元一次方程(
专业!!)。我们只要知道滚动的位置,就可以计算出对应位置的状态值(如:透明度值,tanslate
距离值等)有如下函数:
javascriptfunction createAnimation(startY,endY,startVal,endVal) { return (scrollY)=>{ if (scrollY<startY) return startVal if (scrollY>endY) return endVal return startVal + (endVal-startVal)*(scrollY -startY)/(endY-startY) } }
设置函数构建
style
样式javascriptconst getContainerAnimation = (scrollStart,scrollEnd,dom)=>{ const opacityAnimation = createAnimation(scrollStart,scrollEnd,0,1) const scale = createAnimation(scrollStart,scrollEnd,0.8,1) const opacity = (scroll)=>{ const opacityVal = opacityAnimation(scroll) return opacityVal } const transform = (scroll)=>{ const scaleVal = scale(scroll) return `scale(${scaleVal})` } return { opacity, transform } }
返回一个对象,我们给每一个需要动画的
dom
准备一个该对象,监听滚动时,不断遍历dom
对应对象里面的函数更新样式。初始化map,需要计算起始位置和结束位置
javascriptconst animationMap = new Map() const updateMap = ()=>{ animationMap.clear() const playGroungdReact = dom_playGround.getBoundingClientRect() const scrollStart = playGroungdReact.top + window.scrollY const scrollEnd = playGroungdReact.bottom + window.scrollY - window.innerHeight for (const item of dom_items) { animationMap.set(item,getDomAnimation(scrollStart,scrollEnd,item)) } // 设置box动画... }
遍历跟新样式
javascriptconst updateStyle = ()=>{ const scroll = window.scrollY for (const [dom,value] of animationMap) { for (const prop in value) { if (Object.hasOwnProperty.call(value, prop)) { dom.style[prop] = value[prop](scroll) } } } } window.addEventListener('scroll',updateStyle)