# webPack Svg 在 vue cli 中使用svg ,通常都會有 `img` 、 `svg`...等等做法,直接使用 `svg` 相對的會增加 code行數 可以使用 `svg-sprite-loader` 來解決,svg 客製化 icon的問題,好處有 code 更好讀 可以設定 id ,重複使用 可變更顏色或是尺寸 ## 工作原理 原理: 利用 `svg` 的 `symbol` ,將icon包在 `symbol`內,再用 `use` 使用 `symbol` 補 : <a href="https://www.zhangxinxu.com/wordpress/2014/07/introduce-svg-sprite-technology/">未來必熱: SVG SPRITES </a> 實際打包成的 svg 會是這種格式 ``` html <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <symbol class="icon" viewBox="0 0 1024 1024" id="icon名">{{省略的icon path}}</symbol> <symbol class="icon" viewBox="0 0 1024 1024" id="icon名">{{省略的icon path}}</symbol> </svg> ``` 實例使用方式 ```pug svg use(xlink:href="#symbolId") ``` ## 使用流程 ### .svg 製作 ai 產出svg,svg 格式大致上如下 ``` html <?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 35.6 30.7" style="enable-background:new 0 0 35.6 30.7;" xml:space="preserve"> <style type="text/css"> .st0{opacity:0.5;fill:#F7F8F8;} .st1{fill:#F7F8F8;} </style> <path class="st1" d="M2.9,2.4C9.1-3.2,17.9,2.5,17.9,5c0-2.4,8.6-8.2,14.8-2.6c5.4,4.9,2.4,11.9-2.8,17.1c-4.1,4.1-12,11.2-12,11.2 S9.8,23.6,5.7,19.5C0.5,14.3-2.6,7.3,2.9,2.4z"/> </svg> ``` ### .svg 整理 .svg 內的 `style`、`fill` 、`class` 需要移除掉 ![](http://10.159.1.83:4999/server/../Public/Uploads/2019-09-05/5d70ce0f6f6b1.png) 補 : <a href="https://www.zhangxinxu.com/wordpress/2016/02/svg-compress-tool-svgo-experience/">SVG精簡壓縮工具與svgo 簡介</a> ### svg-sprite-loader install 套件 npm install svg-sprite-loader -D ### svg-loader 配置 在 `Vue.config.js` 配置 ``` javaScript const path = require('path') function resolve(dir) { return path.join(__dirname, './', dir) } module.exports = { chainWebpack: config => { // set svg-sprite-loader config.module .rule('svg') .exclude.add(resolve('src/assets/svg'))// loader處理的目錄 .end() config.module .rule('icons') .test(/\.svg$/) .include.add(resolve('src/assets/svg')) // loader處理的目錄 .end() .use('svg-sprite-loader') .loader('svg-sprite-loader') .options({ symbolId: 'icon-[name]' }) .end() }, configureWebpack: { resolve: { alias: { '@svg': '@/assets/svg' } } }, } ``` `main.js` 配置 ``` javaScript import Vue from 'vue'; import '@svg/index' import App from './App.vue'; import router from './router/router'; import store from './vuex/store'; ``` `svg/index` 配置 ![](http://10.159.1.83:4999/server/../Public/Uploads/2019-09-05/5d70d34aef71e.png) ``` javaScript const requireAll = requireContext => requireContext.keys().map(requireContext); // import all svg const req = require.context('./', true, /\.svg$/); requireAll(req); // console.log(req.keys()) ``` ### SvgIcon Components `vue cli Components` 配置 ``` javaScript <template lang='pug'> svg( :class="svgClass" aria-hidden="true" :fill="svgColor") use(:xlink:href="iconName") </template> <script> export default { name: 'SvgIcon', props: { iconClass: { type: String, required: true }, className: { type: String, default: '' }, svgColor:{ type: String, default: '#fff' } }, computed: { iconName() { return `#icon-${this.iconClass}` }, svgClass() { if (this.className) { return 'svg-icon ' + this.className } else { return 'svg-icon' } } } } </script> <style scoped> .svg-icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style> ``` `typeScript & vue cli ` 配置 ``` javaScript <template lang='pug'> svg( :class="svgClass" aria-hidden="true" :fill="svgColor") use(:xlink:href="iconName") </template> <script lang='ts'> import { Component, Vue, Prop } from 'vue-property-decorator' @Component({ name: 'svgIcon' }) export default class componentName extends Vue { @Prop({ required: true }) private iconClass!: string // icon 名稱 @Prop({ default: '' }) private className!: string // className @Prop({ default: '#fff' }) private svgColor!: string // svg Fill 沒傳預設是白色(#fff) // computed get iconName() { return `#icon-${this.iconClass}` } get svgClass() { if (this.className) { return 'svg-icon ' + this.className } else { return 'svg-icon' } } } </script> <style scoped lang="sass"> svg[class*="icon"] width: 2rem height: 2rem margin-left: .75rem overflow: hidden </style> // 父層使用 svg-icon( class-name="nav_description" icon-class="search_ico") ``` ## 補 ### .svg 合併 <a href="https://www.zhangxinxu.com/sp/svgo/">線上 SVG 合併工具</a> 可用線上工具合併 SVG,合併要用的 svg,之後再 import 到 main.js上,即可全域使用