内容简介:tag: Web; JavaScript; SVG; DOM; 动画 SVG最近在项目中遇到了「带动画 SVG 图标」与 「image」标签结合使用的场景,使用过程中发现水还是有点深,因此整理出来,供有相似场景的童鞋以参考。我们这里有一个的带动画SVG 文件
tag: Web; JavaScript; SVG; DOM; 动画 SVG
最近在项目中遇到了「带动画 SVG 图标」与 「image」标签结合使用的场景,使用过程中发现水还是有点深,因此整理出来,供有相似场景的童鞋以参考。
问题背景
我们这里有一个的带动画SVG 文件
这是一个水波纹效果的 SVG,动画时长是固定的,但是我们希望不同的标记动画的播放时长可以略有不同,进而产生错落交错的感觉。期待效果如下:
其中控制动画时长的属性是写死在 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 浏览器,其他浏览器未做测试。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Beetl 2.9.0 发布,修改 HTML 标签的渲染机制
- Beetl 2.9.0 发布,修改 HTML 标签的渲染机制
- 在整个 Git 仓库的历史(包括所有分支和标签)中修改提交作者的信息(姓名和邮箱)
- HTML5常用标签(2-4)链接标签及多媒体标签
- 基于标签特定文本表示的文本多标签分类
- HTML5常用标签(2-3)图片标签
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。