js 动画

博客分类: 江河计划

js 动画

算法

数组是否存在重复元素

    var containsDuplicate = function (nums) {
        const set = new Set(nums)
        return set.size != nums.length
    };

只出现一次的数字

    var singleNumber = function(nums) {
        let result = 0;
        nums.forEach(el => (result ^= el));
        return result;
    };

js 动画

首先问自己一个问题有了 css 动画为什么还需要用 js 的动画?

两者其实会有自己的适用场景。

css 动画:适用于两个简单状态的平滑过度,或者是几个关键帧的处理。第一个是用 transition。第二个是用 animation。而且 css 做的动画偏自动化一些。中途如果需要根据状态来判断就不适用了

js 动画:适用于复杂场景的动画,如果需要交互介入就需要 js 的动画了。更高级一些的是现在的 3D 动画。

setTimeout、setInterval

将动画分成诊之后,其实就是每隔多少秒调用一次,上述两个方法在 js 中就是每隔多久调用一次。早期使用这两个方法每隔多少时间进行一次状态的改变。调用 DOM 或者调用 CSSOM,改变当前元素的状态。高度、宽度的改变就是动画

但是如果单个 setInterval 计算太多。就会出现有些 setInterval 丢帧。因为上一个 setInterval 还没有执行,后面的就已经执行过了,造成某些过程跳过,就是跳帧了。

用 setTimeout 模拟 setInterval 这样会防止丢帧,因为下一次 setTimeout 一定要等上一次执行完了才会执行。但是 setTimeout 中的计算太过集中的话就会出现动画卡顿,因为下一帧动画迟迟没有来。

requestAnimationFrame

上述的问题都是因为 js 的执行是分片的。会把执行放在每一个运行单元里,因为 js 是自动 GC,并且页面会有每隔一个 FPS 进行一次屏幕重绘,所以所有的状态都会在那个时刻绘上去。所以 setTimeout 和 setInterval 的问题其实是出在或快或慢于每帧的绘制

后来就有了 requestAnimationFrame API,由于上述问题,所以需要在每次执行动画刷新帧之前执行一帧的状态。如果执行超过当前帧的执行时间,浏览器会停止计算执行,去执行重绘和重排页面。以保证用户看到的页面不会被卡顿。

所以 requestAnimationFrame 用来做 js 的动画是最适合的。但是每次回调里的内容不宜太多涉及到计算。如果有计算最好以异步的方式去执行,而 API 里只是去获取当前应该展示的状态。

GreenSock 的 TweenMax

这是一个动画库,用户自动处理 js 动画的库。用于指定一个 dom 在一段时间点里,将状态改成另一个的状态,实际上就是将两个状态取出来,用时间除一下次时间段里变化的状态,然后每隔一段时间叠加。

    TweenMax.to(this.$refs.mask, 0.3, {
        opacity: 1
    });

还可以将动画分解成一个时间段,将每个状态分成百分比,然后设置当前的进度

    var tl = new TweenMax.TimelineLite();
    var aaa = { x: 100 }
    tl.to(aaa, 1, {
        x: 300,
        // autoAlpha: 0
    })
    .to($box, 1, {
        x: '+=200px',
        // autoAlpha: 1
    });
    tl.pause();
    tl.progress(20%);

gsap 里还有很多动画值得探索,常规的动画都能找到

主轴动画

在这里我自创了一个概念,主轴动画,在做动画时。先找到当前动画中时间线最长的动画,将这个动画的过程作为主轴。将这个动画的时间分成 1-100%,甚至粒度可以更细。然后其他的动画的进度也做成 1-100% 的进度,称为附属动画。

主轴动画随着某些条件来动。比如时间、滚动条。随着时间的变动来设置百分比。附属动画监听主轴动画的百分比变化来设置自己的动画时机。

这个动画就变得可控。更加大型的动画,也可以再分模块,一个主轴附属几个小的主轴,然后更小动画再随着小主轴再动。