前端实现CSS3逐帧动画

内容分享1个月前发布
0 0 0

00:00

大家好,我是yangyang.今天给大家上面视频中GIF动图的效果的实现.

效果素材要求

素材是类似雪碧图的方式,图上有n帧形状

前端实现CSS3逐帧动画

实现方法

前端实现CSS3逐帧动画

合适的做法,是将所有的动画帧合并成一张图,通过改变background-position的值来实现动画帧切换。因此,逐帧动画也被称为“精灵动画(sprite animation)”。

通过css3动画

width: 32px; height: 32px;:设置元素的宽度和高度为 32 像素(可以根据实际图片帧的大小设置)

  • background-size: 32px 800px;:指定背景图片的尺寸,第一个参数表明宽度为 32 像素,第二个参数表明高度为 800 像素。(根据实际图片的高度设置,也可以设置实际高度的倍数)
  • 设置动画效果,bear 是动画名称,1s 表明动画持续时间为 1 秒,steps(4, end) 表明动画采用 4 步,每一步切换到最后一帧,infinite 表明动画无限循环播放。

    定义动画的最后一帧,设置背景图片位置为 0, -800px,表明在 Y 轴上向上移动 800 像素.

    .marker-animate-gif {
      width: 32px;
      height: 32px;
      background-size: 32px 800px;
      cursor: pointer;
      overflow: visible;
      opacity: 1;
      margin: 0 auto;
      visibility: visible;
      pointer-events: auto;
      animation: bear 1s steps(4, end) infinite;
      & ~ .marker-title {
        margin: 0 auto;
      }
      // 0% 20% 40% 80% 100%
      // 0 ~ 20
      // 20 ~ 40
      // 40 ~ 80
      // 80 ~ 100
      @keyframes bear {
        100% {
          background-position: 0, -800px;
        }
      }

    通过requestAnimationFrame循环调用实现

    前端实现CSS3逐帧动画

    1. constructor(width, sleep = 0.2, size = 21):接受三个参数,分别是图标的宽度、每帧动画间隔的时间(默认为 0.2 秒)、动画的总帧数(默认为 21)。
    2. begin():开始播放动画的方法。它第一查询所有具有 .marker-animate-gif 类的元素,然后调用 animate() 方法开始动画播放。
    3. animate(timestamp):动画播放函数,接受一个时间戳参数。它通过计算时间戳的差值来控制动画的播放速度。如果已经过了指定的时间间隔或是第一帧,就会更新每个动画元素的背景位置以实现动画效果。最后,通过调用 requestAnimationFrame() 方法循环调用自身,实现动画的持续播放
    
    export default class AnimateIcon {
        constructor(width, sleep = 0.2, size = 21) {
            // const gifItems = this.gifItems()
            // this.icons = gifItems.filter(item =>  iconKeys.include(item.key))
            this.sleep = sleep
            this.width = width
            this.size = size
            this.timer = null
            this.start = undefined
        }
        begin() {
            const elements = document.querySelectorAll('.marker-animate-gif')
            if (!elements.length) {
                return false
            }
            this.frame = 0
            this.timer = requestAnimationFrame(this.animate.bind(this))
        }
        animate(timestamp) {
            if (this.start === undefined) {
                this.start = timestamp
            }
    
            const elapsed = timestamp - this.start
            if (elapsed > 1000 * this.sleep || this.frame === 0) { 
                const elements = document.querySelectorAll('.marker-animate-gif')
                elements.forEach(element => {
                    const width = element.clientWidth
                    // const maxPos = width * this.size
                    let yPos = 0
                    if (this.frame >= this.size) {
                        this.frame = 0
                    }
        
                    yPos = (this.frame) * width // yPos >= maxPos ? maxPos : 
                    element.style.backgroundPosition = `0 -${yPos}px`
                    this.frame++
                })
                this.start = undefined
            }
    
    
            requestAnimationFrame(this.animate.bind(this))
        }
    }
    

    通过setInterval实现

    setInterval实现更为简单

    function spotGifAnimate(size = 50, step =21) {
        if (SpotIconCurrFrame < step) {
            SpotIconCurrFrame++;
        } else {
            SpotIconCurrFrame = 0;
        }
        $(".marker-animate-gif").css("background-position", - size * SpotIconCurrFrame + 'px');
    }
    timer = setInterval(spotGifAnimate, 40)
    © 版权声明

    相关文章

    暂无评论

    您必须登录才能参与评论!
    立即登录
    none
    暂无评论...