SVG 在 image 标签中的动态修改技巧

栏目: 后端 · 前端 · 发布时间: 7年前

内容简介:tag: Web; JavaScript; SVG; DOM; 动画 SVG最近在项目中遇到了「带动画 SVG 图标」与 「image」标签结合使用的场景,使用过程中发现水还是有点深,因此整理出来,供有相似场景的童鞋以参考。我们这里有一个的带动画SVG 文件

tag: Web; JavaScript; SVG; DOM; 动画 SVG

最近在项目中遇到了「带动画 SVG 图标」与 「image」标签结合使用的场景,使用过程中发现水还是有点深,因此整理出来,供有相似场景的童鞋以参考。

问题背景

我们这里有一个的带动画SVG 文件

这是一个水波纹效果的 SVG,动画时长是固定的,但是我们希望不同的标记动画的播放时长可以略有不同,进而产生错落交错的感觉。期待效果如下:

SVG 在 image 标签中的动态修改技巧

其中控制动画时长的属性是写死在 SVG 文件中的(animate 标签的 dur 属性)。SVG 部分内容如下:

<circle cx="22" cy="22" r="6" stroke-opacity="0">
    <animate attributeName="r"
         begin="1.5s" dur="3s"
         values="6;22"
         calcMode="linear"
         repeatCount="indefinite" />
    <animate attributeName="stroke-opacity"
         begin="1.5s" dur="3s"
         values="1;0" calcMode="linear"
         repeatCount="indefinite" />
</circle>
复制代码

另外受限于组件要求,仅能使用 image 标签进行加载 SVG。因此只能从 image.src 属性作为突破入口。

解题思路

先确定基本思路:在 SVG 被插入到 image 标签前,修改 SVG 文件中动画 animate 标签的属性 dur,以达到修改动画时间的目的。

那么我们先来看下 image 加载 SVG 文件几种的方式。

1. image 的 src 直接指定文件路径

<img src="./assets/rings.svg">
复制代码

这种方式加载出来的 SVG 内容没法被 JS 获取到,更不要提修改属性,因此该方案 放弃 。

2. 直接加载 base64 或者 Blob URL 字符串

这种方式中,依靠的是 image 标签支持 base64 和 Blob 类型 URL 的特性。

考虑可以先将 SVG 文件转换为对应的字符串,然后通过正则表达式将动画属性修改,然后传入 src 中来实现。不过这种方式需要编写复杂的正则表达式,并且字符串形式的 SVG 内容可读性较差,因此这种方式也 不是最优的 。

如果可以先以 dom 形式修改 SVG 的动画属性,再将 dom 转换为字符串,最后再将字符串转换为 base64 或者 Blob 类型,就可以实现以上的需求了。

看起来这个思路靠谱,那么就按照这个方向继续探索。

处理过程

1. 获取 dom

获取 SVG 的方式有很多,但获取方式不在本文重点,故只给出原生 JS 实现方式。

const xhr = new XMLHttpRequest();
xhr.addEventListener('load', () => {
  const resXML = xhr.responseXML;
  const svgDom = resXML.documentElement.cloneNode(true);
});
xhr.open('GET', './rings.svg');
xhr.send();
复制代码

2. 修改 dom

上文获取的 svgDom 就是可操作的 dom 节点,接下来和操作 dom 一样来操作它。

// 获取 svg 中的 animate 标签,使用 setAttribute 进行修改 dur、begin 等属性,以下代码仅为示例
// 获取 animation 节点
const ani = svgDom.children[0];
// 修改节点上的动画时长 dur 属性
ani.setAttribute('dur', Math.random() + 2 + 's');
复制代码

3. 转换 domString

接来下便需要将 dom 转换成字符串:通过 XMLSerializer 将 XML 转换成 String 类型。

const svgStr = new XMLSerializer().serializeToString(svgDom);
复制代码

4. 转换 URL

但是上面的 svgStr 是没法直接传给 image.src 的,需要将其转换为 image 可以解析的 base64 或者 Blob URL 类型。

方案 A:

这里我选择了 Blob 类型进行转换,先用 new Blob([svgStr]) 转换成 Blob 类型,再通过 URL.createObjectURL(blob) 方法将字符串转换成 Blob 类型 URL 传入。

const blob = new Blob([svgStr], {
    type: 'image/svg+xml'
});
const blobStr = URL.createObjectURL(blob);
const template = `<img src="${blobStr}">`;
// 最后插入模板
复制代码

方案 B:

当然除了使用 Blob 数据类型外,我们也可以使用 window.btoa() 方法将 svgStr 转换为 base64 类型传入。

const base64 = window.btoa(svgStr);
const template = `<img src="data:image/svg+xml;base64,${base64}">`
// 最后插入模板
复制代码

结论

通过「读入 SVG -> 修改属性 -> 转换 URL -> 传入 image」 这样一个流程,最终实现了我们的预期。

以上思路希望对有类似场景的同学们有所启发。 最后强调的是使用环境为 Chrome 浏览器,其他浏览器未做测试。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

统计思维

统计思维

[美] Allen B. Downey / 金迎 / 人民邮电出版社 / 2015-9 / 49.00元

现实工作中,人们常常需要用数据说话。可是,数据自己不会说话,需要人对它进行分析和挖掘才能找到有价值的信息。概率统计是数据分析的通用语言,是大数据时代预测未来的根基。如果你有编程背景,就能以概率和统计学为工具,将数据转化为有用的信息和知识,让数据说话。本书介绍了如何借助计算而非数学方法,使用Python语言对数据进行统计分析。 通过书中有趣的案例,你可以学到探索性数据分析的整个过程,从数据收集......一起来看看 《统计思维》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试