使用React Hooks和WAAPI创建动效

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

早期在Web页面或Web应用中实现 Web动画 通常是使用JavaScript来完成。使用JavaScript创建动画非常灵活,但不能轻易地让浏览器通过硬件加速来优化动画,也不能将其连接到 布局渲染 管道中。值得庆幸的是,自2007年Webkit团队引入的 CSS AnimationCSS Transition 克服了早期JavaScript动画实现的挑战。但是,CSS Animation和Transition也有很多的限制,特别是在 动态创建动画、控制动画的回放和监视动画生命周期方面等。不过,Web Animation API的出现,让开发者(特别是Web动画方面的开发者)看到了曙光。因为,Web Animation API引入了一种新的解决方案,它提供了CSS Animation和Transition的优化能力,同时还提供了早期基于JavaScript制作动画的API的灵活性。Web Animation API通过 计时模型(Timing Mode)动画模型(Animation Model)提供对Web动画开发和控制。

随着iOS 13.4、iPadOS 13.4和Safari 13.1在macOS Catalina 10.15.4中的发布,Web Animation API得到了所有主流浏览器的支持,也就是说,我们可以在Web动画的开发中大胆的使用该技术了。

只不过现在前端开发都依赖于主流的JavaScript框架进行开发,比如React、Vue等。如果你在React或Vue中开发Web动画的话,你会发现处理动画的方式也会有所不同。比如说,在Vue中有内置的<transition><transition-group>组件,允许使用CSS和JavaScript钩子处理动画;如果使用React,那么对于ReactCSSTransitionGroup一定不会感到陌生,而且在React中还有很多优秀的库用来实现Web动画,比如 React-MotionReact-Gsap-Enhancer。那么在这篇文章中,将和大家一起探讨一下在React中如何使用React的钩子函数和Web Animation API结合起来创建一个高性能的动效。

React Hooks

Hook是React 16.8 的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性

因为我们后面的内容会涉及到React的Hooks相关的知识,如果你从未接触过的话,建议你花点时间阅读:

CSS Animation 和 Transition

Webkit团队早在2007年就提出了CSS AnimationTransition的原始提案,经过多年发展,这些规范已经成熟并成为W3C标准和Web平台不可或缺的一部分。

有了这些技术,在Web开发中集成动画变得很简单,开发人员不再需要编写JavaScript,同时允许浏览器在渲染动画时启动硬件加速(3D加速),并在布局和渲染管道中集成动画,从而提供更好的性能。

虽然CSS Animation和Transition都能实现Web动效,但他们有着明显的区别:

简单地说:

  • CSS的transition只有两个状态:开始状态结束状态;但animation可能是多个状态,有帧的概念
  • CSS的transition需要借助别的方式来触发,比如CSS的状态选择器(如:hover)或 借助JavaScript来触发;animation可以自动触发

用一个真正的示例来展示两者的区别:

正如前面所言,可以使用animationtransition制作Web动画,不过使用animation制作Web动画的场景更多。也正因为如此,业内有一个使用animation制作Web动画的库,即@Daniel Eden的 Animate.css

这个动画库内置了很多动画效果。

为什么要特别提到这个动画库呢?那是因为我们后面的内容将会用到这个库。

@Daniel Eden的 Animate.css 到目前为止,最新的版本是V4版本,而且使用的方式也相对于以前更为灵活,具体的使用指南可以查阅官方文档

Web Animation API

作为一名Web开发人员,我很喜欢CSS Animation和Transition的简单性和卓越性能,而且我也一直在探讨这方面的技术。在一直以来的学习和探讨当中,CSS Animation 和 Transition的这些优势使得Web动画成为Web开发人员的强大工具;但在日常的学习和开发过程中,我也发现了这些技术也存在一定的缺陷:动态创建、回放控制和监控动画的生命周期

不过值得庆幸的是,Web Animation API(简称 WAAPI)的出现可以解决上述提到的这些缺陷。

我们先来看看WAAPI的基础操作。

使用CSS的animation创建动画,首先会先使用@keyframes创建一个动画,然后在需要使用这个动画的元素(对象)上通过animation属性来调用,比如上面的示例:

@keyframes boxScale {
    to {
        transform: scale(1.5, 1.5);
    }
}

.box {
    transform-origin: center;
    animation: boxScale 2s linear infinite alternate;
}

.box元素是先放大,再回到初始大小,再放大,再回到初始大小,一直重复这样的过程:

对于这样的一个效果,如果我们使用WAAPI来实现的话,将会像下面这样:

const aniElement = document.querySelector(".waapi");

const keyframes = [
    { transform: "scale(1, 1)" },
    { transform: "scale(1.5, 1.5)" }
];

const options = {
    duration: 2000,
    iterations: Infinity,
    easing: "linear",
    direction: "alternate"
};

aniElement.animate(keyframes, options);

效果如下:

从效果上来看,他们是相同的。但熟悉CSS Animation的开发者都知道,CSS允许你很容易地将状态变化(比如上示中的圆变大变大)动画化,但如果给定动画的开始值和结束值事先不知道,那么就会非常棘手。针对于这种情况,Web开发者会用CSS Transition来处理这些情况:

// 设置transition属性的初始值
aniElement.style.transitionProperty = 'transform'
aniElement.style.transitionDuration = '2s'
aniElement.style.transform = 'scale(1, 1)'

// 现在,设置transition属性的结束值
aniElement.style.transform = 'scale(1.5, 1.5)'

我们可能通过事件的操作,即将最终值放到对应的事件中:

play.addEventListener("click", () => {
    aniElement.style.transform = "scale(1.5, 1.5)";
});

reset.addEventListener("click", () => {
    aniElement.style.transform = "scale(1, 1)";
});

效果如下:

虽然说,这样能让元素动起来。但浏览器不会在它认为最合适的时候让元素动起来。比如说,如果页面的另一部分也需要创建一个类似的动画,那么我们将要不断的重复这样的代码,这将增加了代码量而且也有可能降低Web性能。当然,你也可有会考虑使用CSS Animation来替代(即,首先@keyframes创建一个动画),并将其插入到<style>.css中,从而无法封装单个元素的真正目标样式更改,并导致昂贵的样式无效。

不过,我们改用Web Animation API,就能轻易让浏览器引擎高效地运行动画,同时还能更好的控制动画。正如上面的示例所示,我们可以使用Element.animate()调用一个方法来重写上面的代码:

element.animate({
    transform: [
        'scale(1, 1)',
        'scale(1.5, 1.5)'
    ]
}, 2000)

这是一个很简单的示例,但可以说Element.animate()方法是名副其实的瑞士军刀,它具有更高级的特性。Element.animate()方法接受两个参数,第一个参数指定是类似于@keyframes动画值,第二个参数指定的指定动画的特性的相关参数(类似于animation-timing-functionanimation-durationanimation-fill-mode等)。这样一来,我们可以添加更多的参数,让上面的动画变得更强大:

const aniElement = document.querySelector(".box");
const play = document.getElementById("play");
const reset = document.getElementById("reset");

play.addEventListener("click", () => {
    aniElement.animate(
        {
            transform: ["scale(1, 1)", "scale(1.5, 1.5)"]
        },
        {
            duration: 2000,
            fill: "both"
        }
    );
});

reset.addEventListener("click", () => {
    aniElement.animate(
        {
            transform: ["scale(1.5, 1.5)", "scale(1, 1)"]
        },
        {
            duration: 2000,
            fill: "both"
        }
    );
});

效果如下:

剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/react/create-highly-performant-animations-using-web-animations-api-and-reack-hooks.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部