资讯专栏INFORMATION COLUMN

React Web 动画的 5 种创建方式,每一种都不简单

solocoder / 1339人阅读

摘要:以前一直投入在中,写动画的时候不是用中的,就是依赖像这样的库,最近转向,在得到很多大佬关于动画的回应,于是决定分享给大家,如有其他见解,非常欢迎在下面评论中交流以下便是本文要分享的创建动画的几种方式下面,勒次个特斯大特一特给元素添加是最简单

以前一直投入在 React Native 中,写动画的时候不是用 CSS 中的 transitions / animations,就是依赖像 GreenSock 这样的库,最近转向 Web,在 Tweet 得到很多大佬关于 React Web 动画 的回应,于是决定分享给大家,如有其他见解,非常欢迎在下面评论中交流

以下便是本文要分享的创建 React 动画 的几种方式

CSS animation

JS Style

React Motion

Animated

Velocity React

下面,勒次个特斯大特一特

CSS animation

给元素添加 class 是最简单,最常见的书写方式。如果你的 app 正在使用 CSS,那么这将是你最愉快的选择

赞同者: 我们只需修改 opacitytransform 这样的属性,就可构建基本的动画,而且,在组件中,我们可以非常容易地通过 state 去更新这些值

反对者:这种方式并不跨平台,在 React Native 中就不适用,而且,对于较复杂的动画,这种方式难以控制

接下来,我们通过一个实例来体验一下这种创建方式:当 input focus 的时候,我们增加它的宽度

首先,我们要创建两个 input 要用到的 class

.input {
  width: 150px;
  padding: 10px;
  font-size: 20px;
  border: none;
  border-radius: 4px;
  background-color: #ffffdffffd;
  transition: width .35s linear;
  outline: none;
}

.input-focused {
  width: 240px;
}

一个是它原始的样式,一个是它 focus 后的样式

下面,我们就开始书写我们的 React 组件

在此,推荐一个 在线的 React VS Code IDE,真的很强大,读者不想构建自己的 React app,可以在其中检验以下代码的正确性

class App extends Component {
  state = {
    focused: false,
  }

  componentDidMount() {
    this._input.addEventListener("focus", this.focus);
    this._input.addEventListener("blur", this.focus);
  }

  focus = () => {
    this.setState(prevState => ({
      focused: !prevState.focused,
    }));
  }

  render() {
    return (
      
this._input = input} className={["input", this.state.focused && "input-focused"].join(" ")} />
); } }

我们有一个 focusedstate,初始值为 false,我们通过更新该值来创建我们的动画

componentDidMount 中,我们添加两个监听器,一个 focus,一个 blur,指定的回调函数都focus

focus 方法会获取之前 focused 的值,并负责切换该值

render 中,我们通过 state 来改变 inputclassNames,从而实现我们的动画

JS Style

JavaScipt stylesCSS 中的 classes 类似,在 JS 文件中,我们就可以拥有所有逻辑

赞同者:跟 CSS 动画 一样,且它的表现更加清晰。它也不失为一个好方法,可以不必依赖任何 CSS

反对者:跟 CSS 动画 一样,也是不跨平台的,且动画一旦复杂,也难以控制

在下面的实例中,我们将创建一个 input,当用户输入时,我们将一个 buttondisable 转变为 enable

class App extends Component {
  state = {
    disabled: true,
  }

  onChange = (e) => {
    const length = e.target.value.length;

    if (length > 0) {
      this.setState({ disabled: false });
    } else {
      this.setState({ disabled: true });
    }
  }
  render() {
    const { disabled } = this.state;
    const label = disabled ? "Disabled" : "Submit";

    return (
      
); } } const styles = { App: { display: "flex", justifyContent: "left", }, input: { marginRight: 10, padding: 10, width: 190, fontSize: 20, border: "none", backgroundColor: "#ffffd", outline: "none", }, button: { width: 90, height: 43, fontSize: 17, border: "none", borderRadius: 4, transition: ".25s all", cursor: "pointer", }, buttonEnabled: { width: 120, backgroundColor: "#ffc107", } }

我们有一个 disabledstate,初始值为 true

onChange 方法会获取用户的输入,当输入非空时,就切换 disabled 的值

根据 disabled 的值,确定是否将 buttonEnabled 添加到 button

React Motion

React Motion 是 Cheng Lou 书写的一个非常不错的开源项目。它的思想是你可以对Motion 组件 进行简单的样式设置,然后你就可以在回调函数中通过这些值,享受动画带来的乐趣

对于绝大多数的动画组件,我们往往不希望对动画属性(宽高、颜色等)的变化时间做硬编码处理,react-motion 提供的 spring 函数就是用来解决这一需求的,它可以逼真地模仿真实的物理效果,也就是我们常见的各类缓动效果

下面是一个森破的示例


  {
    ({ x }) =>
      
}

这是官方提供的几个 demo,真的可以是不看不知道,一看吓一跳

Chat Heads

Draggable Balls

TodoMVC List Transition

Water Ripples

Draggable List

赞同者React Motion 可以在 React Web 中使用,也可以在 React Native 中使用,因为它是跨平台的。其中的 spring 概念最开始对我来说感觉挺陌生,然而上手之后,发现它真的很神奇,并且,它有很详细的 API

反对者:在某些情况下,他不如纯 CSS / JS 动画,虽然它有不错的 API,容易上手,但也需要学习成本

为了使用它,首先我们要用 yarnnpm 安装它

yarn add react-motion

在下面的实例中,我们将创建一个 dropdown 菜单,当点击按钮时,下拉菜单友好展开

class App extends Component {
  state = {
    height: 38,
  }

  animate = () => {
    this.setState((state) => ({ height: state.height === 233 ? 38 : 233 }));
  }

  render() {
    return (
      
Animate
{ ({ height }) =>

Selection 1

Selection 2

Selection 3

Selection 4

Selection 5

Selection 6

}
); } } const styles = { menu: { marginTop: 20, width: 300, border: "2px solid #ffffd", overflow: "hidden", }, button: { display: "flex", width: 200, height: 45, justifyContent: "center", alignItems: "center", border: "none", borderRadius: 4, backgroundColor: "#ffc107", cursor: "pointer", }, selection: { margin: 0, padding: 10, borderBottom: "1px solid #ededed", }, }

我们从 react-motion 中 import Motionspring

我们有一个 heightstate,初始值为 38,代表 menu 的高度

animate 方法设置 menuheight,如果 原 height38,则设置 新 height233,如果 原 height233,则设置 新 height38

render 中,我们使用 Motion 组件 包装整个 p 标签 列表,将 this.state.height 的当前值设为组件的 height,然后在组件的回调函数中使用该值作为整个下拉的高度

当按钮被点击时,我们通过 this.animate 切换下拉的高度

Animated

Animated 是基于 React Native 使用的同一个动画库建立起来的

它背后的思想是创建声明式动画,通过传递配置对象来控制动画

赞同者跨平台,它在 React Native 中已经非常稳定,如果你在 React Native 中使用过,那么你将不用再重复学习。其中的 interpolate 是一个神奇的插值函数,我们将在下面看到

反对者:基于 Twitter 的交流,它目前貌似不是 100% 的稳定,在老的浏览器中的,存在前缀性能的问题,而且,它也有学习成本

为了使用 Animated,我们首先还是要用 yarnnpm 安装它

yarn add animated

在下面的实例中,我们将模拟在提交表单成功后显示的动画 message

import Animated from "animated/lib/targets/react-dom";
import Easing from "animated/lib/Easing";

class AnimatedApp extends Component {
  animatedValue = new Animated.Value(0);

  animate = () => {
    this.animatedValue.setValue(0);

    Animated.timing(
      this.animatedValue,
      {
        toValue: 1,
        duration: 1000,
        easing: Easing.elastic(1),
      }
    ).start();
  }

  render() {
    const marginLeft = this.animatedValue.interpolate({
      inputRange: [0, 1],
      outputRange: [-120, 0],
    });

    return (
      
Animate

Thanks for your submission!

); } } const styles = { button: { display: "flex", width: 125, height: 50, justifyContent: "center", alignItems: "center", border: "none", borderRadius: 4, backgroundColor: "#ffc107", cursor: "pointer", }, box: { display: "inline-block", marginTop: 10, padding: "0.6rem 2rem", fontSize:"0.8rem", border: "1px #eee solid", borderRadius: 4, boxShadow: "0 2px 8px rgba(0,0,0,.2)", }, }

animated 中 import AnimatedEasing

new Animated.Value(0) 创建一个值为 0 的类属性 - animatedValue

创建 animate 方法,处理所有的动画,首先通过 this.animatedValue.setValue(0) 初始化动画值,实现的效果就是每次重新执行该动画,然后调用 Animated.timinganimatedValue 作为第一个参数传递,配置对象 作为第二个参数,一个设置最终动画值,一个设置持续时间,一个设置缓动效果

render 中,我们用 interpolate 方法创建 marginLeft 对象,包含 inputRangeoutputRange 数组,我们使用此对象作为 UImessagestyle 属性

我们使用 Animated.div 替代默认的 div

我们将 animatedValuemarginLeft 作为 Animated.divstyle 属性

Velocity React

Velocity React 是基于已经存在的 Velocity 建立起来的

赞同者:上手容易,API 简单明了,相对其他库更易于掌握

反对者:有些不得不克服的问题,比如 componentDidMount 后动画并没有真正地起作用等,而且,它不跨平台

下面是一个森破的示例


  

首先还是要用 yarnnpm 安装它

yarn add velocity-react

在下面的实例中,我们将创建一个很酷的动画输入

import { VelocityComponent } from "velocity-react";

const VelocityLetter = ({ letter }) => (
  
    

{letter}

) class VelocityApp extends Component { state = { letters: [], } onChange = (e) => { const letters = e.target.value.split(""); const arr = []; letters.forEach((l, i) => { arr.push() }); this.setState({ letters: arr }); } render() { return (
{ this.state.letters }
); } } const styles = { input: { marginBottom: 20, padding: 8, width: 200, height: 40, fontSize: 22, backgroundColor: "#ffffd", border: "none", outline: "none", }, letters: { display: "flex", height: 140, }, letter: { marginTop: 100, fontSize: 22, whiteSpace: "pre", opacity: 0, } }

velocity-react 中 import VelocityComponent

我们要创建一个可重复使用的组件来满足每个 letter 的动画

在这个组件中,我们将 animationopacity 设为 1marginTop 设为 0,这些值代表着传入子组件的重写值,即当组件被创建时,组件的 opacity 会由初始的 0 变为 1marginTop 会由初始的 100 变为 0,我们还设置了 500 ms 的持续时间,最后值得一提的是 runOnMount 属性,它的意思是在组件 挂载创建 完后执行该动画

其中的 onChange 方法会获取用户的每次输入,并创建一个由 VelocityLetter 组成的新数组

render 中,我们就使用该数组在 UI 中渲染 letters

总结

总的来说,基本的动画,我会选择 JS style,复杂的动画,我更偏向 React Motion。而对于 React Native,我还是坚持使用 Animated,一旦 Animated 成熟,在 Web 中可能也会投入使用,目前,我真的很享受 React Motion

原文链接: React Animations in Depth (Nader Dabit)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87263.html

相关文章

  • 2017-08-14 前端日报

    摘要:前端日报精选新特性一览动画的种创建方式,每一种都不简单精读,和它们在之中的优先级变量作用域与提升变量的生命周期详解让完成背景图加载完毕后显示之解析的原理中文深入理解笔记改进数组的功能百度外卖前端周刊第期知乎专栏基础继承基础作用域和 2017-08-14 前端日报 精选 ES8 新特性一览React Web 动画的 5 种创建方式,每一种都不简单精读 React functional s...

    garfileo 评论0 收藏0
  • react动画难写?试试react版transformjs

    摘要:童鞋已经造了个版本。这里很明显,方案和方案可应对简单场景如没有回调等,方案可编程性最大,最灵活,可以适合复杂的动画场景或者承受复杂的交互场景。主要是那上面的演示和传统的直接操作的方式对比。注释里已经写了这是优化重点。 简介 transformjs在非react领域用得风生水起,那么react技术栈的同学能用上吗?答案是可以的。junexie童鞋已经造了个react版本。 动画实现方式 ...

    elarity 评论0 收藏0
  • 关于单页面应用一些随想

    摘要:前面不短时间持续投入了时间在做应用架构方面的考量一个是冒险进行了一次应用架构的调整另一个是跟进了的进展当然实际上是同一个事情也许错过的比收获的还多一些不过能走到现在也算幸运了毕竟单页面应用还面临很多不成熟之处国庆长假过去不少现在的想法估计会 前面不短时间持续投入了时间在做 React 应用架构方面的考量一个是冒险进行了一次应用架构的调整, 另一个是跟进了 Redux 的进展当然, 实际...

    AaronYuan 评论0 收藏0
  • 这样做动画交互,一点都不费力!

    摘要:图层信息第一层动画图层图层类型动画该图层起始关键帧该图层结束关键帧开始第层动画如何动起来时序图利用属性动画控制进度,每次进度改变通知到每一层,触发重绘。对于简单的动画,在实际使用时性能不太明显。 本文由云+社区发表作者:paulzeng 导语:Lottie是Airbnb开源的一个面向 iOS、Android、React Native 的动画库,可实现非常复杂的动画,使用也及其简单,极大...

    Meathill 评论0 收藏0
  • React VR 快速入门完全教程

    摘要:快速入门什么是是一个开放源代码的库,为呈现的数据提供了视图渲染。最后,项目根组件应该通过来进行注册,以便能够进行打包和正常运行。基本思想是渲染一个立方体,并将观众置于中心,随后移动。表示从指定方向平均照亮所有物体的光源。 React VR 快速入门 什么是React React是一个开放源代码的JavaScript库,为HTML呈现的数据提供了视图渲染。React视图通常使用指定的像H...

    andot 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<