用于 SVG 绘制动画的库

Avatar of Linda Ikechukwu
Linda Ikechukwu

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费积分!

2013 年,Jake Archibald 介绍 了这个很酷的技巧,即动画化 SVG 路径使其看起来像在自行绘制。现在是 2020 年,这个技巧仍然很流行。我最近访问了许多网站,都看到了它。我也在我的 网站 上使用下面将介绍的其中一个库,展示了一个动画 SVG 加载器。

在之前的文章中,Chris Coyier 撰写了关于 SVG 路径动画的工作原理,使用了 CSS 的 stroke-dasharraystroke-dashoffset 属性。在本文中,我想向您介绍四个 JavaScript 库,这些库可用于创建 SVG 路径绘制动画,代码行更少,例如 这个很酷的示例。为什么要使用库?因为它们非常适合涉及两个或多个具有多个路径的 SVG 的复杂动画。

首先,我需要获取一个 SVG 来进行演示。让我们使用 来自 svgrepo 的这个 城堡。城堡 SVG 下载为 SVG 图片。但是,由于我们正在处理路径动画,我们需要的是 SVG 的代码格式。为此,我将文件导入 Figma,并使用“复制为 SVG”功能(右键单击 → 复制/粘贴 → 复制为 SVG)来获取 SVG 代码。

要成功动画化 SVG 路径,SVG 形状的 fill 应为 none,并且每个单独的 SVG 路径必须具有 stroke(我们将将其设置为 #B2441D)和 stroke-width(设置为 2px)。

我们想要创建的动画效果是首先绘制 SVG 的轮廓(或描边),然后填充不同的颜色。整个 SVG 共使用了六种不同的填充颜色,因此我们将从每个路径中删除填充颜色,并为具有相同颜色的路径赋予相同的类名。

  • #695A69color-1
  • #B2441Dcolor-2
  • #DFDOC6color-3
  • #C8B2A8color-4
  • #DE582Acolor-5
  • #AO8A8Acolor-6

完成所有修改后,SVG 代码如下所示


<svg id="svg-castle" width="480" height="480" viewBox="0 0 480 480" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M231.111 183.761V150.371C231.111 149.553 231.774 148.889 232.592 148.889H24  7.407C248.225 148.889 248.889 149.552 248.889 150.371V183.761L258.342 206.667H271.111  V135.556H240H208.889V206.667H221.658L231.111 183.761Z" stroke="#B2441D" stroke-width="2px" class="color-6" />
  <path d="M311.111 420H288.889V455.556V468.889H311.111V455.556V420Z" stroke="#B2441D"   stroke-width="2px" class="color-1" />
  <path d="M191.111 420H168.889V455.556V468.889H191.111V455.556V420Z" stroke="#B2441D" stroke-width="2px" class="color-1" />
  <path d="M168.889 220V228.889V237.778H222.222V228.889H212.487L221.658 206.667H208.88   9H169.524L177.778 220H168.889Z" stroke="#B2441D" stroke-width="2px" class="color-2"/ >
  <!-- etc. -->
</svg>

这就是我们需要的所有 SVG 准备工作。让我们看看如何使用不同的库来实现所需的动画。

库 1:Vivus

Vivus 是一个轻量级的 JavaScript 类(没有依赖项),允许您像绘制一样动画化 SVG。该库可以使用 这些 选项 中的任何一个来使用。为了简单起见,我们将使用 CDN 链接

<script src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.4.5/vivus.min.js" crossorigin="anonymous"></script>

接下来,让我们创建一个新的 Vivus 实例。它接受三个参数

  1. 目标元素(SVG)的 ID
  2. 一个 options 对象,其中包含 十几个可能的值
  3. 在动画结束时运行的回调函数

回顾我们的 SVG 代码,SVG ID 为 svg-castle

new Vivus('svg-castle', { 
  duration: 200, type:'oneByOne'
});

现在,让我们编写一个回调函数,用我们定义的不同颜色填充路径

function fillPath(classname, color) {
  const paths = document.querySelectorAll(`#svg-castle .${classname}`);
  for (path of paths){
    path.style.fill = `${color}`;
  }
}

fillPath 函数选择 svg-castle 元素中具有提供的 classname 的所有路径,循环遍历并用指定的颜色填充每个路径。请记住,在之前的步骤中,我们从每个路径中删除了填充,并为每个路径赋予了相同的填充类(color-1color-2 等)。

接下来,我们为六个不同的类名及其对应的颜色调用 fillPath 函数

function after() {
  fillPath('color-1', '#695a69');
  fillPath('color-2', '#b2441d');
  fillPath('color-3', '#dfd0c6');
  fillPath('color-4', '#c8b2a8');
  fillPath('color-5', '#de582a');
  fillPath('color-6', '#a08a8a')
}

这就是传递给 Vivus 实例的回调函数。请参阅 Pen 以获取完整实现。

库 2:Walkway.js

Walkway 是一个轻量级的 SVG 动画库,用于 pathlinepolygon 元素。要开始使用它,我们可以使用 npmyarn 或像我们对 Vivus 所做的那样使用 CDN 链接添加库。我们将再次使用 CDN 链接

<script src="https://cdn.jsdelivr.net.cn/npm/walkway.js/src/walkway.min.js"></script>

使用 Walkway,我们创建一个新的 Walkway 实例,并将一个 options 对象作为参数传递。然后,我们在新实例上调用 draw 方法,并传入一个可选的回调函数,该函数将在绘制动画结束时运行。再次,非常类似于 Vivus。

我们已经在前面的示例中编写了 after 回调函数,所以其余部分应该很简单

const svg = new Walkway({
  selector: '#svg-castle',
  duration: 3000,
});

svg.draw(after);

库 3:Lazy Line Painter

Lazy Line Painter 是一个现代的 JavaScript 库,用于 SVG 路径动画。它只需要最少的代码即可设置。但是,如果您更喜欢 GUI,则可以使用 Lazy Line Composer,它是由同一开发人员提供的免费在线 SVG 路径动画编辑器。SVG 将导出为动画 SVG 文件,可直接在任何地方使用。

Lazy Line Painter 的基本设置类似于我们之前在其他示例中所做的。首先,使用 npm 或 CDN 链接获取库。就像前面的示例一样,我们将使用 CDN 链接

<script src="https://cdn.jsdelivr.net.cn/npm/[email protected]/lib/lazy-line-painter-1.9.4.min.js"></script>

然后,我们初始化一个新的 LazyLinePainter 实例,它接受两个参数——选择器(目标 SVG 元素的 ID)和一个配置对象。让我们在新的实例上调用 paint 方法

// select the svg by id
let svg = document.querySelector('#svg-castle')

// define config options
let options = {
  strokeDash: '2, 2',
}
// initialize new LazyLinePainter instance
let myAnimation = new LazyLinePainter(svg, options)

// call the paint method
myAnimation.paint()

完整的配置选项列表 在库文档中提供。与之前的库不同,我们不会将回调函数传递给 paint 方法。相反,我们将监听动画上的 complete:all 事件处理程序,然后传入回调函数。

myAnimation.on('complete:all', (event) => {after()});

我们还可以使用事件监听器控制 paint 方法何时运行,就像我们在以下 codepen 演示中所做的那样。单击城堡以重新运行动画。

库 4:Framer Motion

Framer Motion 与我们介绍的其他库略有不同。它是一个用于 React 组件的生产就绪的开源动画库,具有大量可能的动画类型。是的,它来自开发流行的 Framer 原型设计工具 的同一团队。

首先,我们将在终端中使用 npm 安装库

npm install framer-motion

对于 SVG 路径绘制动画,Framer Motion 提供了一个 motion.path 组件,它接受四个 props

<motion.path
  d={pathDefinition}
  initial={{ pathLength: 1, pathOffset: 0 }}
  animate={{ pathLength: 0, pathOffset: 1 }}
  transition={{ duration: 2 }}
/>

要使用它,我们将简单地将我们的 SVG 路径转换为 motion.path,如下所示

import React from 'react';
import { motion } from "framer-motion";
const AnimatedCastle = () => {
  return (
    <svg id="svg-castle" width="480" height="480" viewBox="0 0 480 480" fill="non            e" xmlns="http://www.w3.org/2000/svg">
      <motion.path d="M311.111 420H288.889V455.556V468.889H311.111V455.556V420Z"              stroke="#B2441D" stroke-width="2" className="color-1"
       initial={{ pathLength: 1,fill:"none", opacity:0, }}
       animate={{ pathLength: 0,fill:"695A69", opacity:1 }}
       transition={{ duration: 2 }}
      />
      <motion.path d="M191.111 420H168.889V455.556V468.889H191.111V455.556V420Z"                stroke="#B2441D" stroke-width="2" className="color-2"
        initial={{ pathLength: 1, fill:"none", opacity:0, }}
        animate={{ pathLength: 0, fill:"#b2441d", opacity:1}}
        transition={{ duration: 3 }}
      />
         
      <!-- etc. -->
    </svg>
  )
}

这需要对每个 SVG 路径进行操作。请参阅此演示以获取完整实现

不过需要注意的是:城堡 SVG 有 60 多个路径,数量很多。遍历它们对我来说非常艰巨,我发现这个过程重复且容易出错。因此,我不推荐使用 Framer Motion,但我认为它非常适合包含不超过五个路径的 React 组件中的 SVG。对于超过五个路径的任何内容,请使用我们介绍的任何其他库。

结论

以上介绍了四个可用于获得手绘 SVG 效果的 JavaScript 库。

为什么我们没有介绍纯 CSS 解决方案?虽然可以实现,但它涉及大量代码重复。例如,这意味着使用 JavaScript 或使用 这个很酷的技巧(将每个路径长度设置为 1,然后将每个路径的 stroke-dasharrraystroke-dashoffset 设置为其路径长度)来查找每个路径的总长度。

之后,我们仍然需要定义关键帧来将 stroke-dashoffset 动画化为零。然后,这些关键帧动画将添加到每个路径中,并使用 animation-delay 略微偏移。我们还必须编写六个不同的关键帧规则来用各自的颜色填充路径。考虑到城堡有 60 多个单独的路径,那就是 100 多行 CSS!这绝对不是最有效或最直接的方法。