1. 为什么要在UniApp里折腾SVG?
如果你做过几个UniApp项目,肯定遇到过图标问题。UI给了一堆图标,有PNG,有JPG,偶尔还会甩过来几个SVG文件。PNG用起来简单,<image>标签一放,完事。但一到需要换主题、夜间模式,或者根据用户操作动态改变图标颜色的时候,PNG就傻眼了——你得让UI重新切一套图,或者自己用PS捣鼓半天,费时费力。
SVG就不一样了。它本质上是一段用代码描述的矢量图形,就像你用HTML和CSS画一个图形一样。既然是代码,那就能改!颜色、大小、甚至形状,都可以通过JavaScript动态调整。想象一下,你的App有个收藏按钮,用户点击后,图标从灰色空心变成红色实心。用SVG,你只需要改一下fill属性的颜色值,瞬间完成,一套图标走天下,再也不用为不同状态准备多套切图了。
但问题来了,UniApp本身对SVG的支持并不像在Web端那么直接。你不能像在浏览器里那样,直接把<svg>标签写在<template>里就完事(在App端和部分小程序平台会不识别或渲染异常)。所以,我们得绕点路,用一些“黑科技”把SVG用起来,并且还要用得爽,能动态改颜色。这就是我们今天要聊的核心:在UniApp里,如何把SVG代码变成能用的图片,并且能像变魔术一样随时改变它的颜色。
我刚开始也踩过坑,试过各种组件库,有的太重,有的兼容性不好。后来摸索出一套自己封装工具函数的方法,实测下来非常稳,从H5到微信小程序、App都没问题。接下来,我就把这套实战经验掰开揉碎了讲给你听,保证你跟着做就能搞定。
2. 核心原理:把SVG“变”成背景图
为什么不能直接用SVG标签?主要是因为跨平台兼容性。UniApp最终要编译到不同的终端(H5、各家小程序、App),这些平台对<svg>标签的解析和支持程度不一。最稳妥、兼容性最好的方案,是把SVG转换成一种所有平台都认识的东西——Data URL,然后作为CSS的背景图(background-image)来使用。
你可以把Data URL想象成一个“自包含”的URL。它不像http://xxx.png那样指向一个外部文件,而是直接把文件内容(经过编码)写在URL里。对于SVG,它的Data URL格式长这样:
data:image/svg+xml,<svg代码>
浏览器或小程序引擎看到这个data:image/svg+xml开头,就知道后面跟着的是SVG的源代码,会把它解析成一幅图片。
所以,我们的核心思路就两步:
- 编码转换:把原始的SVG代码字符串,进行URL编码,让它能安全地放在一个URL里(比如处理掉特殊字符
#,<,>等)。 - 拼接使用:拼成完整的
data:image/svg+xml,<编码后的字符串>,然后扔给background-image。
这样一来,无论在哪端,渲染的都是一个标准的背景图片,兼容性问题迎刃而解。动态修改颜色的魔法,也将在第一步的“编码转换”前后施展。
2.1 第一步:封装一个万能的SVG转URL函数
这个函数是基础中的基础,我把它放在项目的公共工具文件里,比如common/function.js或utils/index.js,方便全局调用。
// common/function.js
export default {
/**
* 将SVG字符串转换为可用的Data URL
* @param {string} svgString - 原始的SVG代码字符串
* @returns {string} - 处理后的Data URL字符串
*/
svgToUrl(svgString) {
if (!svgString) return '';
// 1. 清理和压缩SVG字符串
let encoded = svgString
.replace(/<!--.*-->/g, '') // 移除注释
.replace(/[\r\n]/g, ' ') // 换行符转空格,压缩体积
.replace(/\s+/g, ' ') // 多个空格合并为一个,进一步压缩
.replace(/"/g, "'") // 双引号转单引号,避免与外套引号冲突
// 2. 对URL关键保留字符进行百分号编码(这是关键!)
encoded = encoded
.replace(/%/g, '%25')
.replace(/&/g, '%26')
.replace(/#/g, '%23')
.replace(/{/g, '%7B')
.replace(/}/g, '%7D')
.replace(/</g, '%3C')
.replace(/>/g, '%3E');
// 3. 拼接成完整的Data URL
// 注意:这里返回的字符串前后**不要**加引号,在模板中绑定样式时会自动处理。
return `data:image/svg+xml,${encoded}`;
}
}
<


533

被折叠的 条评论
为什么被折叠?



