---
# System prepended metadata

title: webPack Svg

---

# 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上，即可全域使用