前言
最近在做專案的優化升級,因為折騰了一下午的圖示管理,所以就把自己的經驗分享出來,希望可以幫助大家更快的解決自己的需求。
我現在的專案,都是引入iconfont的圖示庫,真是的好用又方便。現在有三種模式,使用方法可以在官網的 使用說明 頁檢視。我們今天主要討論的主要是第三種,也就是svg圖示的優化。
簡單封裝元件
使用說明裡有提及,我們引入官方生成的庫檔案路徑。寫好css樣式,頁面程式碼引用如下:
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
</svg>
複製程式碼
我們簡單的做一個元件封裝如下:
// SvgIcon.vue
<template>
<svg class="icon">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
props: {
fontClass: {
required: true,
type: String
},
className: {
type: String,
default: ""
}
},
computed: {
iconName() {
return `#icon-${this.fontClass}`;
}
}
};
</script>
<style>
.icon {
width: 40px;
height: 40px;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
複製程式碼
將該元件註冊為全域性元件。新建資料夾,路徑為src/icons
。在其中新建一個index.js檔案。
// icons/index.js
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon.vue'
Vue.component('svg-icon', SvgIcon)
複製程式碼
在main.js
中,我們引入這個index.js
import './icons/index.js'
複製程式碼
這樣我們就可以在檔案中隨意使用svg-icon
元件了。
使用svg-sprite-loader
現在我們的svg檔案是整體的,每當我們修改的時候,需要在iconfont上生成新的整體檔案。那麼是否能需要用一個icon的時候,就自己手動加一個呢?然後自動打包成一個整體檔案。webpack可以幫我們實現。
首先,我們新建一個資料夾專門來放置單個svg檔案。
如圖,引入了多個從iconfont中下載的彩色圖示svg檔案。我們使用svg-sprite-loader
來把所有的單個svg合成為整體的svg雪碧檔案。可以先看vue-cli3中的關於svg的預設配置(通過 vue inspect
命令檢視,也可以在 vue ui
的介面中點選檢視):
/* config.module.rule('svg') */
{
"test": /\.(svg)(\?.*)?$/,
"use": [
{
"loader": "file-loader",
"options": {
"name": "img/[name].[hash:8].[ext]"
}
}
]
},
複製程式碼
現在我們在vue.config.js
檔案中,來改寫一下這個配置。
chainWebpack: config => {
// 我們先刪除原有的svg rule。
config.module.rules.delete('svg')
config.module
.rule('svg-sprite-loader')
.test(/\.svg$/)
.include.add(resolve('src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
// 但我們有的svg可能並不都是圖示。我們的需要對icons/svg以外的svg檔案做處理。我們把images的rule新增上svg格式。
const imagesRule = config.module.rule('images')
imagesRule.exclude.add(resolve('src/icons'))
config.module
.rule('images')
.test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/)
}
複製程式碼
現在我們只要import進這個svg檔案就可以使用了。
import "@/icons/sun.svg";
// 使用
<svg class="icon">
<use xlink:href="#sun"></use>
</svg>
複製程式碼
自動匯入webpack的require.context
上面示例中我們是手動import
一個圖示,但一旦圖示多起來,手動操作就太不優雅了。我們可以使用webpack自帶的require.context
功能來實現自動匯入功能。
// icons/index.js
//(建立出)一個 context,其中檔案來自 svg 目錄,不包含子目錄,request 以 `.svg` 結尾。
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)
複製程式碼
圖示再多,都可以毫無煩惱啦~~~
進一步壓縮 svgo-loader
其實我們引入的單個svg檔案中有很多無用的資訊。
svg-sprite-loader
也做了相關處理,但是它只提取到path
標籤整體,如果path路徑內包含的無用的註釋資訊,如:<path><!-- 無用資訊--></path>
依舊存在。
我們可以使用 svgo-loader
來進一步精簡svg的內容。刪除掉path
標籤內的註釋資訊。配置如下:
// vue.config.js
chainWebpack: config => {
config.module.rules.delete('svg')
config.module
.rule('svg-sprite-loader')
.test(/\.svg$/)
.include.add(resolve('src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
.use('svgo-loader')
.loader('svgo-loader')
.end()
}
複製程式碼
好了,這裡就是所有關於svg圖示使用和優化的全部內容了。如果有更好的方案和問題,歡迎大家指出和分享。