如何在微信小程序中使用iconfont的彩色svg图标

684 阅读3分钟

简介

最近在进行微信小程序开发的时候使用到了iconfont的彩色图标,彩色图标是SVG格式的。在小程序中使用SVG的问题就不做过多说明了,网上亦有多种方案,下面分享下个人实现的方案。

思路

  1. image标签的src属性使用data类型URL
  2. 从iconfont中获取图标转换成dataUrl,并以js的方式存放
  3. 创建一个自定义组件,在组件中使用图标

实现

1. 如何获取图标

因为iconfont中支持按项目的方式将图标整体打包,在网页中提供了体验用的cdn地址,我们需要下载图标时可直接从该地址中下载。

方法: 在项目中选中 Symbol,点击查看在线图标 即可获取在线链接,复制下面的cdn地址,用于后续下载。

b09c6e46757ba4b2a1dd7acffdcdf69.png

2. 下载并生成图标js文件

为了方便以后每次操作,我们编写一个node程序,用于下载并生js文件,下面提供程序代码:

//从命令行参数中读取url,保存目录信息
let [, , url, saveDir] = process.argv
const https = require('https')
const fs = require('fs')
const path = require('path')
saveDir = saveDir || './'

//下载
function download(url) {
  return new Promise((resolve, reject) => {

    https.get(`https:${url}`, res => {
      const data = []
      console.log("开始下载...");
      res.on('data', chunk => {
        data.push(chunk)
      })

      res.on('end', chunk => {
        console.log("下载完成...");
        const content = Buffer.concat(data).toString()
        resolve(content);
      })
    }).on('error', (e) => {
      reject(e);
    });
  })
}

//生成js文件
function createData(icons) {
  const file = [];
  const iconList = [];
  icons.forEach(icon => {
    iconList.push(`"${icon.name}":"${icon.url}"`)
  })
  file.push("const icons = { \n", iconList.join(",\n"), "\n}\n")
  file.push("export default icons")
  return file.join('')
}

//保存文件
function save(data, name, dir) {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true })
  }

  const d = new Uint8Array(Buffer.from(data, 'utf-8'));
  const fullPath = path.resolve(dir, name)
  fs.writeFile(fullPath, d, (err) => {
    if (err) throw err;
    console.log('保存成功!');
    console.log('保存路径:' + path.resolve(fullPath));
  });
}


async function main() {
  const content = await download(url)
  //分析js内容,根据内容,获取里面svg图标部分数据
  const [, symbolsContent] = content.match(/<svg>(.*)<\/svg>/)
  //将多个symbol 拆分
  const symbols = symbolsContent.match(/<symbol (.*?)<\/symbol>/g)
  const icons = []
  symbols.forEach(sym => {
    //获取图标id
    const [, id] = sym.match(/ id="(.*?)" /)
    //使用base64 存放图标数据,此处选用了base64,若是使用原生svg保存,请注意对内容进行 urlencode,若有需要,可自行修改代码
    const svg = 'data:image/svg+xml;base64,' + Buffer.from(sym.replaceAll('symbol', 'svg ').replace(/^<svg/, '<svg  xmlns="http://www.w3.org/2000/svg"   xmlns:xlink="http://www.w3.org/1999/xlink"'), 'utf-8').toString('base64')

    icons.push({
      name: id,
      url: svg
    })
  });

  //生成js文件
  const data = createData(icons)

  //创建 assets下的资源目录
  save(data, path.basename(url), saveDir)

}

main()

代码主要提供了一种用于下载图标并生成对应js的简单方法,若有其他需求或其他思路可自行修改。

将上面代码保存为 loadIconFont.js 存放于自己喜欢的路径。

执行 node loadIconFont.js //at.alicdn.com/t/c/font_test.js ./ 等待片刻即可在当前目录中获得一份生成好的js文件。

参数分别为 node loadIconFont.js [图标在线连接地址] [保存目录]若使用npm,亦可将该命令写入 package.json 中,此处不做介绍。

node ./loadIconFont.js //at.alicdn.com/t/c/font_test.js ./assets/iconfont
开始下载...
下载完成...
保存成功!
保存路径:F:\miniprogram\assets\iconfont\font_test.js

生成后的font_test.js内容格式为:

const icons = { 
"icon-ppt":"data:image/svg+xml;base64,PHN2ZyAgeG1sb...",
"icon-video":"data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0d...",
"icon-unknown":"data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9I..."
}
export default icons

对应格式为: 图标名称 : svg,其中图标名称根据 iconfont项目中的id生成,即:

1678995148625.png

此时已经完成了图标的下载生成工作,将下载下来的文件保存到自己喜欢的资源目录中,此处保存的目录为项目下的 ./assets/iconfont/font_test.js

3. 创建一个组件,在组件中使用图标

为了更简单地使用图标,可以选择创建一个组件,在组件中使用它,而图标数据,这里选择将其存入到全局数据app.globalData.iconfonts属性中,下面为参考代码

在小程序项目中创建一个叫 svg-icon 的组件,wxml,js 内容如下

components/svg-icon.wxml

<!--components/svg-icon.wxml-->
<view>
  <image src="{{useSrc?src:projects[project][name]}}" style="width:{{width}};height: {{height}};" />
</view>

components/svg-icon.js

// components/svg-icon.js
const app = getApp()
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    name:{
      type: String
    },
    project: String,
    width:{type:String,value:"1rem"},
    height:{type:String,value:"1rem"},
    src: String,
    useSrc: Boolean //让其适应不使用全局图标文件的控制
  },
  /**
   * 组件的初始数据
   */
  data: {
    //图标以不同project的形式进行划分
    projects:app.globalData.iconfonts
  },
  /**
   * 组件的方法列表
   */
  methods: { }
})

定义完成组件后,还需要在app.js中导入图标文件,代码如下:

app.js

//import 图标文件
import {default as font_test } from './assets/iconfont/font_test'
App({
  globalData:{
    iconfonts:{
      "icon-project-1":font_test //图标文件作为一个项目存放于iconfonts属性中,使用 "icon-project-1" 作为项目名称
    },
  },
})

4. 如何使用

  1. 在page中添加组件
{
  "usingComponents": {
    "svg-icon":"/components/svg-icon"
  }
}
  1. 使用组件
      <svg-icon name="icon-ppt" project="icon-project-1" width="1.5rem" height="1.5rem" />

组件属性:

属性名称是否必须说明
name图标名称
project图标项目名称
width
height
src组件使用自定义 src ,仅 use-srctrue 时有效
use-src是否使用src属性

5. 效果

1678995867824.png

总结

到此,实现了在微信小程序中使用iconfont的彩色svg图标的目的,上述代码由于具体情况不尽相同,所以仅作参考,有需要的朋友可以自行进行修改,适应自己的项目。