添加动画
通过以上的方式就实现了一个静态的环形进度条了,接下来就需要它动起来,由于 stroke-dasharray(在这它的值其实就是圆的周长
) 和 stroke-dashoffset 的属性值是需要动态生成的,因此我们得添加一些 JavaScript 代码:
function setProcessCircle(percent = 0) { const processCircle = document.querySelector('.process-circle') // 获取圆的周长 const circumference = processCircle.getTotalLength() // 把周长赋值给 strokeDasharray processCircle.style.strokeDasharray = circumference // 动态计算 offset 赋值给 strokeDashoffset // 为了支持 percent = 0 | '0%',所以使用 parseInt 转换 processCircle.style.strokeDashoffset = circumference * (1 - parseInt(percent) / 100) } 复制代码
效果图中的 html + css
部分就不贴出来了,容易占篇幅。
loading 动画
例如 ElementUI 中 区域加载 的 loading 形式如下:
简单分析
- 观察整体不难发现只需要一个圆形,即使用
<circle>
元素即可 - 其蓝色部分一直在 缩短 或 增长,这点可以通过 stroke-dasharray 和 stroke-dashoffset 属性来实现,同时添加
transition
过渡动画即可 - 最后是每个 缩短 或 增长 的位置不是相同的,那么可以直接用过动画
animation
和roate
来实现停的旋转即可
具体实现
// html <svg stroke-width="3"> <circle cx="50" cy="50" r="20" fill="none" class="circle-loading" ></circle> </svg> // style <style> .circle-loading { stroke-dasharray: 90, 150; stroke-dashoffset: 0; stroke: #409eff; stroke-linecap: round; animation: loading-dash 1.5s ease-in-out infinite, laoding-color 1.5s ease-in-out infinite; } @keyframes laoding-color { 0% { stroke: #de3e35; } 25% { stroke: #ffa500; } 50% { stroke: #ffff00; } 75% { stroke: #008000; } 100% { stroke: #0000ff; } } @keyframes loading-dash { 0% { stroke-dasharray: 1, 200; stroke-dashoffset: 0; } 50% { stroke-dasharray: 90, 150; stroke-dashoffset: -40px; } to { stroke-dasharray: 90, 150; stroke-dashoffset: -120px; } } </style> 复制代码
按钮动效
简单分析
- 外层包裹的矩形可以通过
<rect>
元素实现 - 矩形的线条残缺不完整,可以通过 stroke-dasharray 和 stroke-dashoffset 属性来实现
- 当鼠标放置上去时,产生的动画可通过 animation、stroke-dasharray 、stroke-dashoffset 等属性结合即可
具体实现
// html <svg class="svg-wrap"> <text class="text" x="60" y="75">CLICK HERE</text> <rect class="rect" x="40" y="35" /> </svg> // style <style> .svg-wrap { stroke-width: 3px; background-color: black; } .rect { height: 60px; width: 220px; stroke: #fff; fill: transparent; stroke-dasharray: 220 60; stroke-dashoffset: -260; stroke-width: 4px; } .text { fill: #1287f4; font-size: 30px; } .svg-wrap:hover .rect { animation: line-move 0.5s linear forwards; } .svg-wrap:hover .text{ fill: #fff; transition: all 1s ease-in-out; } @keyframes line-move { 0% { stroke-dasharray: 220 60; stroke-dashoffset: -260; stroke-width: 4px; stroke: #e32727; } to { stroke-dasharray: 560; stroke-dashoffset: 0; stroke-width: 2px; stroke: #1234f4; } } </style> 复制代码
复杂案例实战
以上的基础案例由于涉及的计算不多,因此我们可以人工进行计算宽、高、偏移等等数据,但是针对复杂的内容,很多参数就不是那么容易计算出来了,因此,我们需要一些工具来快速得到一些必要参数,然后我们在基于这些必要参数取做修改,让其产生更丰富的效果即可。
工具推荐
和 SVG 相关的工具就现在来说已经遍地开花了(就好像现在的 ChatGPT、文心一言
),通过搜索引擎查找都能找出来很多,这里也不谈这些工具的优劣了,下面简单列举一些:
- figma:支持浏览器在线,支持客户端下载
- sketch:支持浏览器在线,支持客户端下载(Mac)
- Adobe Illustrator:支持浏览器在线,支持客户端下载
- Pixso:号称 Sketch 的新选择,几乎还原了Sketch 的专业功能
- ...
下面的示例都是基于 figma 来演示的,不再后续赘述。
文字动效
还是同样的第一个案例这里尽量讲详细点,后续案例就不再述说过于详细的内容了。
使用 figma 创建文字路径如下
由于文字内容的路径很难直接计算处理,因此我们可以通过 figma 来帮助我们生成相应的文字路径,大致操作如下:
处理 SVG 代码内容
得到的 SVG 内容大致如下,代码内容比较多这里用图片代替,其中各个内容的对应关系如下所示:
其中的 <mask>
需要去掉,否则文字的颜色值将无法填充。
stroke-dasharray & stroke-dashoffset 属性
由于我们需要让文字具备断续连接的能力,这里还是得使用前面提到 stroke-dasharray 和 stroke-dashoffset 属性来实现,它们的功能前面已经描述过了,也用了几次了,如果你不记得了可以回过头去看看。
但是这里的 stroke-dasharray 和 stroke-dashoffset 的值到底该设置成多少呢?
首先一定是设置成每个文字的长度,那么问题就变成了怎么获取文字的长度了,不用担心,还记得在实现 环形进度条 时用到的 getTotalLength() 方法吗?
这里我们仍然可以使用它来获取每个文字的长度了,代码如下:
const paths = document.querySelectorAll('path') for (const [ptah,index] of paths) { console.log(`path 的路径长度 = ${ptah.getTotalLength()}`) } 输出结果: path 的路径长度 = 179.47874450683594 S path 的路径长度 = 150.7733917236328 V path 的路径长度 = 274.966064453125 G path 的路径长度 = 442.99505615234375 文 path 的路径长度 = 514.3809204101562 字 复制代码
接下来为每个 path 设置样式:
#svg-text > path:nth-of-type(1) { stroke-dasharray: 179.479; stroke-dashoffset: 179.479; } #svg-text > path:nth-of-type(2) { stroke-dasharray: 150.773; stroke-dashoffset: 150.773; } #svg-text > path:nth-of-type(3) { stroke-dasharray: 274.966; stroke-dashoffset: 274.966; } #svg-text > path:nth-of-type(4) { stroke-dasharray: 442.995; stroke-dashoffset: 442.995; } #svg-text > path:nth-of-type(5) { stroke-dasharray: 514.381; stroke-dashoffset: 514.381; } 复制代码
设置了这些值之后,文字内容就会不可见了,而这也是 动画的初始状态。
animation 动画
前面种种操作已经完成了动画的初始状态,接下来我们要添加上 animation 动画,核心改变的就是 stroke-dashoffset 的值,就是把它设置成 0,文字内容就会被从隐藏变成显示,再添加过渡时间就完成了,重复内容就不贴出来了:
#svg-text > path:nth-of-type(1) { /* ... */ animation: text-line 2s ease forwards; } #svg-text > path:nth-of-type(2) { /* ... */ animation: text-line 2s ease forwards 300ms; } #svg-text > path:nth-of-type(3) { /* ... */ animation: text-line 2s ease forwards 600ms; } #svg-text > path:nth-of-type(4) { /* ... */ animation: text-line 2s ease forwards 900ms; } #svg-text > path:nth-of-type(5) { /* ... */ animation: text-line 2s ease forwards 1200ms; } #svg-text{ stroke: #d205f7; fill: none; animation: fill-color 2.5s ease-in forwards; } @keyframes text-line { to { stroke-dashoffset: 0; } } @keyframes fill-color{ to{ stroke: transparent; fill: #d205f7; } } 复制代码
重复的事交给 JavaScript
上面才 5 个文字就需要写那么多的样式,属实不能忍,于是我们可以将重复的部分交给 JavaScript 代码去处理:
<style> #svg-text { stroke: #d205f7; stroke-width: 2px; fill: none; animation: fill-color 2.5s ease-in forwards; } @keyframes text-line { to { stroke-dashoffset: 0; } } @keyframes fill-color { to { stroke: transparent; fill: #d205f7; } } </style> <script> function init() { const paths = Array.from(document.querySelectorAll('path')) paths.forEach((path, index) => { const len = path.getTotalLength() path.style.strokeDasharray = len path.style.strokeDashoffset = len path.style.animation = `text-line 2.5s ease-in forwards ${ index * 300 }ms` }) } init() </script> 复制代码
运动轨迹
简单分析
完成以上效果需要包括以下几个内容:
- 获取 目标物 的 SVG 代码
- 绘制 运动路径
- 让目标物 沿着路径运动
获取目标物的 SVG 代码
这个可以直接从 iconfont 上选择对应的内容,然后复制它的 SVG 代码。
绘制运动路径
运动路径的绘制我们仍然可以通过 SVG 工具 figma 来获取,值得注意的是默认的路径是用还是填充的,真正在应用时可以通过 stroke="transparent"
将路径颜色变成透明色,整体感官更好,大致如下:
让目标物沿着路径运动
针对这种按特定运动轨迹进行的动画,也不需要你去一点点计算了,我们可以借助 GreenSock 中的 motionpath 插件来实现,在其对应的文档中有详细的介绍,核心就是引入以下两个内容:
<div id="app"> <!-- 鸟 --> <svg id="bird" t="1679665908640" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14202" width="100" height="100" > 省略内容 </svg> <!-- 路径 --> <svg width="719" height="419" viewBox="0 0 719 419" fill="none" xmlns="http://www.w3.org/2000/svg" > <path id="path" d="M1 268C146.006 483.259 245.695 450.805 336 268C518.233 -96.9549 599.902 -63.7284 718 222" stroke="transparent" /> </svg> </div> <script src="https://unpkg.co/gsap@3/dist/gsap.min.js"></script> <script src="https://unpkg.com/gsap@3/dist/MotionPathPlugin.min.js"></script> <script> // 注册插件 gsap.registerPlugin(MotionPathPlugin); // 开启动画 gsap.to("#bird", { duration: 5, repeat: 12, repeatDelay: 1, yoyo: true, ease: "power1.inOut", motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], }, }); </script> 复制代码
最后
以上就是本文有关 SVG 基础部分的介绍和使用了,不知道你是入门了,还是被门绊了一下,还是那句话:希望本文对你所有帮助!!!