css requestAnimationFrame

绘制动画,一般有两个选择:

  1. js脚本 setTimeout和setInterval
  2. css3 transition和animation属性

这两个方法有各自的局限性:

  • js脚本实现动画的局限性:
  1. 即使向 setTimeout和setInterval 传递ms级的参数,由于js单线程的关系,可能会引发堵塞,不能达到高精度的准确性
  2. 没有对动画的循环机制进行优化,只是以一个大致的时间间隔循环,而且“最优帧速率”和“选择绘制下一帧的最优时机”都需要开发者自己来控制;ms设置过小,比如小于16.67ms(60帧)那么就会引起掉帧(一般显示器显示最高频率是60帧);设置过大,帧数小,动画效果不流畅
  • css3实现动画的局限性
  1. 兼容性问题,对于PC浏览器,IE8, IE9之流,你想兼容实现某些动画效果,比如说淡入淡出,就无能为力了
  2. 不能应用所有属性问题,CSS3动画可以改变高宽,方位,角度,透明度等等,但是对于scrollTop,就无能无力了
  3. CSS3支持的动画效果有限

于是,我们引入requestAnimationFrame

  1. requestAnimationFrame会把每一帧中的dom操作集中起来,再一次重绘或者重排中就完成,并且刷新频率紧跟浏览器的刷新频率
  2. 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
  3. requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销

requestAnimationFrame的用法与setTimeout相似,只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行

timerID = requestAnimationFrame(callback); 
//控制台输出1和0
var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
console.log(timer);//1

cancelAnimationFrame方法用于取消定时器

//控制台什么都不输出
var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
cancelAnimationFrame(timer);

也可以直接使用返回值进行取消

var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
cancelAnimationFrame(1);

其实我们在《vue 页面加载进度条组件》中使用了setInterval作为动画脚本,现在我们可以用requestAnimationFrame重写(主要是一个递归调用,看mounted和watch中的代码就可以了)

<template>
  <transition name="fade">
    <div class="progress-bar" v-if="isShow">
    </div>
  </transition>
</template>

<script type="text/babel">
  export default {
    data() {
      return {
        isShow: true, // 是否显示进度条
        val: 0, // 进度
      }
    },
    props: {
      /**
       * 每10毫秒自增幅度
       */
      step: {
        type: Number,
        default: 5,
      },
      /**
       * 初始值
       */
      initVal: {
        type: Number,
        default: 0,
      },
      /**
       * 到一定进度停止
       */
      stopVal: {
        type: Number,
        default: 80,
      },
      /**
       * 进度条继续到成功
       */
      isOk: {
        type: Boolean,
        default: false,
      },
    },
    mounted() {
      this.val = this.initVal
      let step =  this.step
      let loop = () => {
        this.val = this.val + step
        this.$el.style.width = this.val + '%'
        if (this.val >= this.stopVal) {
          cancelAnimationFrame(timer)
          return
        }
        requestAnimationFrame(loop)
      }
      let timer = requestAnimationFrame(loop)
    },
    watch: {
      isOk() {
        let val = this.val
        let step =  this.step
        let loop = () => {
          val = val + step
          this.$el.style.width = val + '%'
          if (val >= 100) {
            cancelAnimationFrame(timer)
            this.isShow = false
            this.$emit('callback', 'load success')
            return
          }
          requestAnimationFrame(loop)
        }
        let timer = requestAnimationFrame(loop)
      },
    },
  }
</script>

<style lang="stylus" rel="stylesheet/stylus">
  .progress-bar {
    position fixed
    top 0
    height 6px
    width 0
    background-color #999
  }
  .fade {
    &-enter-active, &-leave-active {
      transition: all .3s
    }
    &-enter, &-leave-active {
      opacity: 0
    }
  }
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值