# 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` 需要移除掉

補 : <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` 配置

``` 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上,即可全域使用