钉钉官网动效简易实现

本文最后更新于 2 年前,文中所描述的信息可能已发生改变。

概述

渡一短视频–钉钉官网动效demo

  1. 动画状态函数
  2. 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为动画的主要部分,动画随着鼠标的滚动开始和结束。可以看到在页面滚动时,动画部分是固定在视口区的。可以布局如下:

  1. list 使用position: sticky 布局
  2. animate-box的高度高一些

animate-box作为list 第一个父级可滚动元素,list会固定在视口区,直到父盒子离开视口,随着父盒子一起离开视。

js动画

  1. 动画的过程为:(开始位置,开始状态)->(结束位置,结束状态),实际上是一个一元一次方程(专业!!)。我们只要知道滚动的位置,就可以计算出对应位置的状态值(如:透明度值,tanslate距离值等)

    有如下函数:

    javascript
    function 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)
     }
    }
  2. 设置函数构建style样式

    javascript
    const 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对应对象里面的函数更新样式。

  3. 初始化map,需要计算起始位置和结束位置

    javascript
    const 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动画...
    }
  4. 遍历跟新样式

    javascript
    const 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)
vue组件库搭建
createVNode/render创建notify组件