如何優(yōu)雅地在微信小程序使用 SVG 字體圖標(biāo)
本文思路來自實(shí)際項(xiàng)目的重構(gòu)總結(jié),歡迎糾正和交流。如果對(duì)你有幫助,還請(qǐng)點(diǎn)贊??收藏支持一下啦。
最近在重構(gòu)一個(gè)項(xiàng)目,主要是做 H5 端和小程序端,這次打算開始多做總結(jié)啦,之前已經(jīng)總結(jié)一篇《如何優(yōu)雅的管理 HTTP 請(qǐng)求和響應(yīng)攔截器?》?。
如果大家還有其他方案,歡迎一起探討哈~ 喜歡本文的朋友給個(gè)贊??鼓勵(lì)一下哈~
一、需求思考和方案設(shè)計(jì)
本文介紹的項(xiàng)目是使用 Taro框架進(jìn)行多端開發(fā),目前主要適配 H5 端和微信小程序端。項(xiàng)目使用的字體圖標(biāo)庫(kù)內(nèi)部維護(hù),目前托管在 iconfont 上。
1. 問題分析
最近在重構(gòu)的項(xiàng)目比較古老(其實(shí)也就去年的),項(xiàng)目中使用到的圖標(biāo)早已更新 N 個(gè)迭代了,已經(jīng)由「單色圖標(biāo)」更新到「多色圖標(biāo)」!
很明顯好看多了。
這里先按照 iconfont 的規(guī)則看看單色圖標(biāo)和多色圖標(biāo)使用上的區(qū)別:
單色圖標(biāo)的使用
單色圖標(biāo)使用起來比較簡(jiǎn)單(以 font-class 引用為例),只需要 2 個(gè)步驟:
- 第一步:拷貝項(xiàng)目下面生成的fontclass代碼:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.css
- 第二步:挑選相應(yīng)圖標(biāo)并獲取類名,應(yīng)用于頁(yè)面:
<i?class="iconfont?icon-xxx">i>
多色圖標(biāo)的使用
多色圖標(biāo)使用起來也很簡(jiǎn)單(以 symbol 引用為例),只需要 3 個(gè)步驟:
- 第一步:拷貝項(xiàng)目下面生成的symbol代碼:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js
- 第二步:加入通用css代碼(引入一次就行):
<style?type="text/css">
????.icon?{
???????width:?1em;?height:?1em;
???????vertical-align:?-0.15em;
???????fill:?currentColor;
???????overflow:?hidden;
????}
style>
- 第三步:挑選相應(yīng)圖標(biāo)并獲取類名,應(yīng)用于頁(yè)面:
<svg?class="icon"?aria-hidden="true">
????<use?xlink:href="#icon-xxx">use>
svg>
這兩種圖標(biāo)在使用上都非常方便,那大家是不是會(huì)好奇,我們寫本文的目的?
原因是,「微信小程序上不支持 SVG 字體圖標(biāo)!?? 而多色圖標(biāo),是需要借助 SVG 標(biāo)簽來實(shí)現(xiàn)?!?/strong>
于是我在小程序文檔找了好久,也只看到了 ?組件能夠使用 SVG,介紹如下:
image圖片。支持 JPG、PNG、SVG、WEBP、GIF 等格式,2.3.0 起支持云文件ID。
其屬性 src?的值為圖片資源地址,這就意味著,不能使用 SVG 字體圖標(biāo)了。因此我們需要想想變通的辦法。
(這里不討論將 iconfont 上圖標(biāo)下載為圖片來引用的情況)
2. 方案設(shè)計(jì)
既然我們了解了單色圖標(biāo)和多色圖標(biāo)的使用方式:
- 單色圖標(biāo):任意標(biāo)簽(如
div?標(biāo)簽) + 對(duì)應(yīng)字體圖標(biāo) class 名稱 - 多色圖標(biāo):使用
svg?標(biāo)簽 +use?標(biāo)簽設(shè)置xlink:href?屬性
首先馬上想到的是,能不能集合兩者使用方式,實(shí)現(xiàn)任意標(biāo)簽通過 class 名稱來使用多色圖標(biāo)?
答案是可以的,只需要對(duì)圖標(biāo)文件進(jìn)行格式轉(zhuǎn)換,即 「將多色字體圖標(biāo)轉(zhuǎn)換為能通過class名稱來引用的字體圖標(biāo)文件」?。
那接下來只要看看如何實(shí)現(xiàn)格式轉(zhuǎn)換即可。
二、重構(gòu)后的效果
這邊我以其中一個(gè)頁(yè)面進(jìn)行重構(gòu),最后將單色圖標(biāo)全都換成新的多色 SVG 字體圖標(biāo),效果如下:

三、方案一:手動(dòng)轉(zhuǎn)換圖標(biāo)文件
目前我嘗試了兩套方案,并且都順利實(shí)現(xiàn)效果,這邊先分享一下這兩種方案,然后再補(bǔ)充說明我選擇哪個(gè)方案和原因:
該方案實(shí)現(xiàn)的是手動(dòng)將字體圖標(biāo)庫(kù)文件轉(zhuǎn)換成能通過 class 名稱來引用的圖標(biāo)庫(kù)。使用到的工具有:
- icomoon:https://icomoon.io/ 用來打包圖標(biāo)。
- transfonter:https://transfonter.org/ 用來生成 base64 格式的圖標(biāo)。
接下來開始試試:
步驟一:通過 iconfont 下載需要的 SVG 格式的圖標(biāo)

這邊多下載了幾個(gè),都是 svg 格式的文件,如下圖:

步驟二:打包字體圖標(biāo)
這一步是將零散個(gè)多個(gè) SVG 多色圖標(biāo)打包成一個(gè)字體圖標(biāo)文件,這一步需要使用 https://icomoon.io/:




步驟三:字體圖標(biāo)進(jìn)行 Base64 編碼
接下來就需要將打好的字體圖標(biāo)進(jìn)行 base64 壓縮,這邊使用https://transfonter.org/來操作。
第一步選擇前面打好的包里面的 .ttf?文件:

設(shè)置參數(shù),并導(dǎo)出文件:

步驟四:合并字體圖標(biāo)
經(jīng)過前面幾個(gè)步驟,我們現(xiàn)在已經(jīng)有 2 個(gè)包:
- 第一個(gè)包:icomoon 生成的包

- 第二個(gè)包:transfonter 生成的包

接下來我們開始將兩個(gè)包合并:將第一個(gè)包 style.css 文件除 @font-face?的內(nèi)容復(fù)制到第二個(gè)包 stylesheet.css 文件后面。

這樣就獲得一份新的字體圖標(biāo)文件,其實(shí)也可以拷貝到一份新的 css 文件中。
使用字體圖標(biāo)
我們將前面修改后的文件改名為 icon.scss?并引入到項(xiàng)目:
//?app.scss
@import?"./style/icon.scss";
代碼中使用圖標(biāo):
"icon-exe-knowledge-ppt">
??<View?className='path1'>View>
??<View?className='path2'>View>
??<View?className='path3'>View>
??<View?className='path4'>View>
??<View?className='path5'>View>
??<View?className='path6'>View>
</View>
最后效果如下:

踩坑記錄
在使用方案一的時(shí)候,踩了好幾個(gè)坑,這邊挑兩個(gè)來說:
- 使用時(shí),需要手動(dòng)添加幾個(gè)
?元素
剛開始使用,圖標(biāo)一直沒有出來,后面觀察字體圖標(biāo),它是在容器元素下很多個(gè) path1?、 path2?等元素的偽類中去渲染圖標(biāo)內(nèi)容:

所以使用時(shí)需要手動(dòng)添加一下。
- 默認(rèn)圖標(biāo)會(huì)是一個(gè)大的塊級(jí)元素,導(dǎo)致圖標(biāo)顯示有問題
這是因?yàn)槭謩?dòng)加的 class 為 path*?的 View?標(biāo)簽本身是塊級(jí)元素,所以這里只要簡(jiǎn)單加個(gè) display: flex?即可。

并且其字體大小,也是可以使用 font-size?來設(shè)置:
display:?flex;
font-size:?100px;
抽取組件
考慮到復(fù)用性,我將這些抽成一個(gè) exe-svg-icon?組件:
import?Taro?from?'@tarojs/taro';
import?{?View,?Text?}?from?'@tarojs/components';
import?classNames?from?'classnames';
function?EXESvgIcon(params)?{
??const?{?icon?=?'exe-none'?}?=?params;
??const?containerStyle?=?{
????display:?'inline-block'
??}
??return?(
????<View?className={classNames('svg',?icon)}?style={containerStyle}>
??????<View?className='path1'?style={containerStyle}>View>
??????<View?className='path2'?style={containerStyle}>View>
??????<View?className='path3'?style={containerStyle}>View>
??????{/*?一般圖標(biāo)?3?層,這邊多預(yù)留幾層,防止不夠用?*/}
??????<View?className='path4'?style={containerStyle}>View>
??????<View?className='path5'?style={containerStyle}>View>
??????<View?className='path6'?style={containerStyle}>View>
??????<View?className='path7'?style={containerStyle}>View>
??????<View?className='path8'?style={containerStyle}>View>
??????<View?className='path9'?style={containerStyle}>View>
????View>
??)
}
export?default?EXESvgIcon;
到這邊,方案一實(shí)現(xiàn)完成。
四、方案二:借助第三方庫(kù)實(shí)現(xiàn)
由于第一個(gè)方案使用起來比較繁瑣,于是我又再研究其他簡(jiǎn)單點(diǎn)的方案。
直到我看到 taro-iconfont-cli 這個(gè)庫(kù)。
在Taro框架中使用iconfont圖標(biāo),不依賴字體,支持多色彩。
目前支持平臺(tái)包括:
- 微信小程序
- 支付寶小程序
- 百度小程序
- 頭條小程序
- QQ小程序
- H5
有以下特性:
- 一鍵生成標(biāo)準(zhǔn)組件,多端支持
- 使用方便,import即可
- 支持多色彩
- 支持自定義顏色
- 支持 ES6 和 TypeScript 兩種模式
按照文檔描述,只需要 3 個(gè)步驟,那么試試看:
步驟一:安裝 taro-iconfont-cli
#?Yarn
yarn?add?taro-iconfont-cli?--dev
#?Npm
npm?install?taro-iconfont-cli?--save-dev
需要注意的是,如果使用的是 Taro 2.x,請(qǐng)安裝 「[email protected]」,并閱讀舊版的README.md。
步驟二:生成配置文件
通過命令生成 iconfont.json 配置文件:
npx?iconfont-init
#?可傳入配置輸出路徑
#?npx?iconfont-init?--output?iconfont.json
此時(shí)項(xiàng)目根目錄會(huì)生成一個(gè)iconfont.json的文件,內(nèi)容如下:
{
??"symbol_url":?"請(qǐng)參考README.md,復(fù)制?http://iconfont.cn?官網(wǎng)提供的JS鏈接",
??"save_dir":?"./src/components/iconfont",
??"use_typescript":?false,
??"platforms":?"*",
??"use_rpx":?true,
??"trim_icon_prefix":?"icon",
??"default_icon_size":?18,
??"design_width":?750
}
symbol_url?值需要在 iconfont 中復(fù)制

步驟三:生成 Taro 標(biāo)準(zhǔn)組件
通過命令,生成 Taro 標(biāo)準(zhǔn)組件:
npx?iconfont-taro
#?可傳入配置文件路徑
#?npx?iconfont-taro?--config?iconfont.json
通過控制臺(tái),我們可以看到 taro-iconfont-cli 為每個(gè)圖標(biāo)單獨(dú)生成一個(gè) Taro 組件:


使用字體圖標(biāo)
按照文檔使用方法,使用的時(shí)候,只需要引入 IconFont?組件,通過 name?名稱來選擇對(duì)應(yīng)圖標(biāo)即可:
//?省略其他代碼
import?IconFont?from?'@components/Iconfont/index';
<IconFont?name="exe-knowledge-ppt">IconFont>
按照文檔提示,還有更多使用方法:
//?原色彩
"alipay"?/>
//?單色:紅色
<IconFont?name="alipay"?color="red"?/>
//?多色:紅色+橘色
<IconFont?name="alipay"?color={['red',?'orange']}?size={300}?/>
//?不同格式的顏色寫法
<IconFont?name="alipay"?color={['#333',?'rgb(50,?124,?39)']}?/>
//?與文字對(duì)齊
<View?style={{?display:?'flex',?alignItems:?'center'?}}>
??<Text>Hellotext>
??<IconFont?name="alipay"?/>
View>
踩坑記錄
- 字體大小設(shè)置問題
由于通過這種方式導(dǎo)出的圖標(biāo),是個(gè)單獨(dú)組件,使用時(shí)如果需要設(shè)置圖標(biāo)大小,需要通過設(shè)置其 width和height屬性進(jìn)行設(shè)置。

通過 font-size屬性無法設(shè)置字體圖標(biāo)的大小。
五、方案對(duì)比和選擇
這次只嘗試了這兩種方案,都能順利完成需求。如果大家有其他方案,歡迎一起評(píng)論區(qū)討論~
接下來「以生成下面相同 20 個(gè)多色圖標(biāo)為標(biāo)準(zhǔn),分析這兩種方案:」

先看看對(duì)比結(jié)果:
| 手動(dòng)轉(zhuǎn)換圖標(biāo)文件 | 借助 taro-iconfont-cli 庫(kù)實(shí)現(xiàn) | |
|---|---|---|
| 生成難易程度 | 復(fù)雜 | 簡(jiǎn)單 |
| 使用難易程度 | 簡(jiǎn)單 | 簡(jiǎn)單 |
| 資源占用程度 | 27kb | 420kb(項(xiàng)目未打包前) |
分析每個(gè)項(xiàng)目:
1. 對(duì)比生成難易程度
- 「手動(dòng)轉(zhuǎn)換圖標(biāo)文件」需要每次將圖標(biāo)單獨(dú)下載,再進(jìn)行打包,當(dāng)圖標(biāo)數(shù)量較多,其工作量就較大。
- 「taro-iconfont-cli」只需設(shè)置字體圖標(biāo)庫(kù)地址,自動(dòng)下載并生成組件,較為方便。
2. 對(duì)比使用難易程度
兩者使用起來都比較簡(jiǎn)單:
- 「手動(dòng)轉(zhuǎn)換圖標(biāo)文件」為元素添加 class 名稱即可。
- 「taro-iconfont-cli」為元素添加 name 屬性。
3. 對(duì)比資源占用情況
資源占用差異就很大了,分析下原因:
- 「手動(dòng)轉(zhuǎn)換圖標(biāo)文件」是將圖標(biāo)重新打包,最后生成的都是 base64 編碼的內(nèi)容,相對(duì)較小。
- 「taro-iconfont-cli」是為每個(gè)圖標(biāo)生成一個(gè)組件,單獨(dú)一個(gè)文件,還有附加各個(gè)平臺(tái)的文件,因此較大。
4. 選擇方案
考慮到目前項(xiàng)目所使用的字體圖標(biāo)比較少(20 個(gè)以內(nèi)),后續(xù)開發(fā)人員上手難度問題,我最終使用「taro-iconfont-cli」這套方案。雖然這個(gè)方案生成的組件資源占用會(huì)稍大,但是目前使用圖標(biāo)較少,并且可以通過打包工具、CDN 等常用優(yōu)化方式進(jìn)行優(yōu)化。
六、本文總結(jié)
本文通過一次簡(jiǎn)單的項(xiàng)目重構(gòu),總結(jié)項(xiàng)目中小程序使用 SVG 多色圖標(biāo)的方案,目的是為了實(shí)現(xiàn)在小程序中能夠正常使用 SVG 多色圖標(biāo),并且也為內(nèi)容越來越多獨(dú)立站點(diǎn)的項(xiàng)目積累經(jīng)驗(yàn),畢竟各個(gè)項(xiàng)目具有相關(guān)性。
最后,「taro-iconfont-cli」方案目前已經(jīng)在內(nèi)部 npm 倉(cāng)庫(kù)維護(hù),采用版本控制,方便不同項(xiàng)目使用時(shí)減少?zèng)_突。
當(dāng)然,本文是基于我的經(jīng)驗(yàn)總結(jié),歡迎大家有更好的方案,一起討論學(xué)習(xí)~~
參考文章
- 微信小程序中使用svg字體圖標(biāo)教程 ——圖解三步,很清晰?(https://blog.csdn.net/Originally_M/article/details/106473475)
- Taro-Iconfont?(https://gitee.com/mirrors/Taro-Iconfont)
