什么是SVG
SVG是”Scalable Vector Graphics”的简称。中文可以理解成“可缩放矢量图形”。是一个基于XML的图形描述语言。它是可以用于描述静态图、动画,以及用户界面的一种图形格式。1999年由万维网联盟发布。于2013年成为W3C推荐标准。
SVG有哪些优势
与其他图像格式相比,使用SVG的优势在于:
- SVG 可被非常多的工具读取和修改
- SVG 与JPEG和GIF图像比起来,尺寸更小,且可压缩性更强。
- SVG 使用 XML 格式定义图形
- SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失
SVG在小程序中的使用
由于前面提到的SVG的特性,因此他被广泛应用于各种开发中,尤其适合各种icon和图标,下面就结合具体的开发记录下小程序中使用SVG的过程。
获取对应SVG代码
//已处理
//未处理
其中最外层的 fill="#000000" 就是SVG的填充色,可以根据需求修改对应的填充颜色(由于示例中的SVG比较简单,因此只有一个填充颜色,并非所有SVG的最外层的fill都是他的填充色)。我们可以直接使用这部分代码,也阔以通过一些SVG优化工具进一步进行优化。
在线压缩
将SVG图片直接拖入页面右侧的画布,他会根据一些通用优化方式对SVG进行初步优化,点击上方的 MAKEUP ,再看我们SVG的代码已经发生了变化(当然这里由于我们的示例图标比较简单,主要是删除了代码间的无效空白)
小程序引用图片的几种方式
首先,我们知道小程序引用图片的方式并不多。目前小程序并不支持直接引用svg文件,也不支持直接引用本地文件。总结下来,可行的方法有如下几种:
img的src引用
- 云文件的cloudID
- 图片的https链接
- 图片base64格式
字体图标
- 阿里的icon就是引用ttf文件,然后在text中使用图标对应的类名
background-image的url属性
- 图片的https链接
- data类型Url
我们知道,如果直接引用图片,是很难修改颜色的,因为每个像素都已经填充了颜色,且进行了压缩。所以排除了img的src引用方式,以及background-image的第一种方式。
我们选择background-image的data类型url,引用svg格式的图片。具体怎么做呢?
首先使用上面获取到的SVG代码,我们需要把这个svg格式先转为data类型的url。可以通过以下网址在线转换: 在线svg内联格式生成。
这一步本质上是先对svg做了url-encode,主要是#这些符号做转义。然后在转义后的字符串前面加上data:image/svg+xml,字样。
转换后的svg格式如下:
background-image: url("data:image/svg+xml, %3Csvg height='24' width='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z'/%3E%3C/svg%3E");
在具体代码中引用SVG
至此我们就完成了在小程序中使用SVG的所有准备工作了,接下来在代码中使用就和普通的css中引用SVG没有太大区别。具体代码如下:
- index.wxml:
在新窗口打开
- index.wxss:
.svg-demo-container {
margin: 50rpx;
width: 300rpx;
display: flex;
align-items: center;
}
.svg-demo-text {
color: #888896;
font-size: 26rpx;
margin-left: 9rpx;
}
.icon-open-new {
background-image: url("data:image/svg+xml, %3Csvg height='24' width='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z'/%3E%3C/svg%3E");
background-size: cover;
}
.icon {
display: inline-block;
width: 50rpx;
height: 50rpx;
}
小程序根据主题色,动态修改svg颜色
按照上述的步骤,我们仅需要稍微改变一下,就可以修改svg的颜色。
原理是:先替换svg文件中所有的十六进制颜色为主题色,然后再填充到background-image的url中即可
。
我们写一个替换颜色的函数:
const changeColor = function(url,color){
let res = url.replace(/%23[a-zA-Z0-9]{6}/g, color.replace("#", "%23"));//转义后的#等于%23,利用正则表达式,替换所有%23后6位为新的十六进制六位数。
return res;
}
然后对index.wxml和index.wxss
进行一些修改:
在新窗口打开
.icon11{
background-size: cover;
display: inline-block;
width: 70rpx;
height: 70rpx;
}
在index.js
中处理相关的逻辑:
const svg = "data:image/svg+xml, %3Csvg height='24' width='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z'/%3E%3C/svg%3E"
data: {
svgData: '"' + svg + '"'
},
onLoad: function (options) {
let svgData = this.changeColor(this.data.svgData, '#707070');
this.setData({
svgData: svgData
})
},
在最后放上一段可以直接将SVG代码转成dataUrl的函数,这样就可以不用每次去打开网站去转换了:
svgData(svg)
{
// 将被设置到 dataset 中的属性还原出来
svg = svg.replace(/data-(.*?=(['"]).*?\2)/g, '$1');
// 将被设置到 data-xlink-href 的属性还原出来
svg = svg.replace(/xlink-href=/g, 'xlink:href=');
// 将 dataset 中被变成 kebab-case 写法的 viewBox 还原出来
svg = svg.replace(/view-box=/g, 'viewBox=');
// 清除 SVG 中不应该显示的 title、desc、defs 元素
svg = svg.replace(/<(title|desc|defs)>[\s\S]*?<\/\1>/g, '');
// 为非标准 XML 的 SVG 添加 xmlns,防止视图层解析出错
if (!/xmlns=/.test(svg)) svg = svg.replace(/
// 对 SVG 中出现的浮点数统一取最多两位小数,缓解数据量过大问题
svg = svg.replace(/\d+\.\d+/g, (match) => parseFloat(parseFloat(match).toFixed(2)));
// 清除注释,缓解数据量过大的问题
svg = svg.replace(//g, '');
// 模拟 HTML 的 white-space 行为,将多个空格或换行符换成一个空格,减少数据量
svg = svg.replace(/\s+/g, " ");
// 对特殊符号进行转义,这里参考了 https://github.com/bhovhannes/svg-url-loader/blob/master/src/loader.js
svg = svg.replace(/[{}\|\\\^~\[\]`"<>#%]/g, function (match) {
return '%' + match[0].charCodeAt(0).toString(16).toUpperCase();
});
// 单引号替换为 \',由于 kbone 的 bug,节点属性中的双引号在生成 outerHTML 时不会被转义导致出错
// 因此 background-image: url( 后面只能跟单引号,所以生成的 URI 内部也就只能用斜杠转义单引号了
svg = svg.replace(/'/g, "\\'");
// 最后添加 mime 头部,变成 Webview 可以识别的 Data URI
return 'data:image/svg+xml,' + svg.trim();
}
方法调用:
let svg= this.svgData('')