首先安装 1 yarn add svg-sprite-loader -D
把 webpack.config.js
翻译成 Vue.config.js
这个库给的示例代码是 webpack.config.js
但是我们现在在用的是 Vue
官方的代码是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { test : /\.svg$/ , loader : 'svg-sprite-loader' , options : { ... } } { test : /\.svg$/ , use : [ { loader : 'svg-sprite-loader' , options : { ... } }, 'svg-transform-loader' , 'svgo-loader' ] }
翻译成 Vue.config.js
,用到的 chainWebpack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const path = require ('path' )module .exports = { lintOnSave : false , chainWebpack : config => { const dir = path.resolve (__dirname, 'src/assets/icons' ) config.module .rule ('svg-sprite' ) .test (/\.svg$/ ) .include .add (dir).end () .use ('svg-sprite-loader' ).loader ('svg-sprite-loader' ).options ({extract :false }).end () config.plugin ('svg-sprite' ).use (require ('svg-sprite-loader/plugin' ), [{plainSprite : true }]) config.module .rule ('svg' ).exclude .add (dir) } }
其他备注
1 2 3 "svg-sprite-loader" : "^6.0.11" , "svgo-loader" : "^2.2.1"
在 shims-vue.d.ts
中添加 这一步是为了解决 ts
报错
1 2 3 4 declare module '*.svg' { const content : string ; export default content; }
接着在 TS
里面引入 1 2 3 4 5 6 7 <script lang="ts"> // 笑死我了,这是菜鸡写法 import x from '@/assets/icons/Labels.svg' import y from '@/assets/icons/Money.svg' console.log(x) console.log(y) </script>
这一步的作用就是在 html
的 head
部分嵌入一个 symbol
,接着我们在 template
里面用 <use />
标签就可以使用啦
1 2 3 4 5 6 7 8 9 <template> <div class="nav"> <router-link to="/money"> <svg> <use xlink:href="#Money" /> </svg> </router-link> </div> </template>
想必看出来了,这样引入真的 很麻烦 ,如果我们有几十个 svg
,难道要一个一个的引入??
而且每次都要写 <svg><use /></svg>
好麻烦,我们可不可以把它封装成一个组件呢?
引入整个 svg
目录? 1 2 3 4 5 6 let importAll = (requireContext : __WebpackModuleApi.RequireContext ) => requireContext.keys ().forEach (requireContext);try {importAll (require .context ('../assets/icons' , true , /\.svg$/ ));} catch (error) {console .log (error);}
将 icon
封装成组件 @/components/Icon.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <template> <svg class="icon"> <use :xlink:href="'#' + name" /> </svg> </template> <script lang="ts"> let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext); // 这玩意是搜的全网搜到的? try {importAll(require.context('../assets/icons', true, /\.svg$/));} catch (error) {console.log(error);} // 如果不加 try,在单元测试的时候可能会遇到问题 export default { name: 'Icon', props: ['name'] // 以下代码是自动生成的 // props: { // name: { // type: String, // required: true // } // } } </script> <style lang="scss" scoped> // 这个样式代码是阿里矢量字体库里面给的css .icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>
@/main.ts
全局注册
1 2 import Icon from "@/components/Icon.vue" ;Vue .component ("Icon" , Icon )
然后直接在 view
里面使用 <Icon />
即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <template> <div class="nav"> <router-link to="/money"> <Icon name="Money"/> </router-link> | <router-link to="/lables"> <Icon name="Labels"/> </router-link> | <router-link to="/statistics"> <Icon name="Statistics"/> </router-link> </div> </template>
遇到的一个小 bug
: fill
颜色 尝试实现切换标签页的时候自动更改填充颜色来达到突出显示的效果
但是并不是所有的 svg 都会自动变色, 只有一些标签会起作用… 于是我直接干脆调成了这样
和这样
笑死我了,直接逃避这个问题
经过排查发现是 svg
代码里面的 fill
属性来控制了颜色,从而 css
不能从外部更改颜色
如图:
手动删掉此属性即可正常用css指定颜色,但是如果有很多svg.这样的话未必太过麻烦
我们可以使用一个叫做 svgo-loader
的插件来解决此问题
不知道是什么原因,高版本的这个插件会导致加载不出 svg 的 bug,我使用的是以下版本,是正常使用的
1 2 3 4 5 6 7 8 9 { "devDependencies" : { "svg-sprite-loader" : "^6.0.11" , "svgo-loader" : "^2.2.1" , } }
我的完整的版本号(可以正常使用的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 { "name" : "morney-3" , "version" : "0.1.0" , "private" : true , "scripts" : { "serve" : "vue-cli-service serve" , "build" : "vue-cli-service build" , "test:unit" : "vue-cli-service test:unit" , "lint" : "vue-cli-service lint" } , "dependencies" : { "core-js" : "3.15.2" , "register-service-worker" : "1.7.2" , "vue" : "2.6.14" , "vue-class-component" : "7.2.6" , "vue-property-decorator" : "9.1.2" , "vue-router" : "3.5.2" , "vuex" : "3.6.2" } , "devDependencies" : { "@types/jest" : "24.0.25" , "@typescript-eslint/eslint-plugin" : "4.28.4" , "@typescript-eslint/parser" : "4.28.4" , "@vue/cli-plugin-babel" : "4.5.13" , "@vue/cli-plugin-eslint" : "4.5.13" , "@vue/cli-plugin-pwa" : "4.5.13" , "@vue/cli-plugin-router" : "4.5.13" , "@vue/cli-plugin-typescript" : "4.5.13" , "@vue/cli-plugin-unit-jest" : "4.5.13" , "@vue/cli-plugin-vuex" : "4.5.13" , "@vue/cli-service" : "4.5.13" , "@vue/eslint-config-typescript" : "7.0.0" , "@vue/test-utils" : "1.2.2" , "eslint" : "6.8.0" , "eslint-plugin-vue" : "6.2.2" , "sass" : "1.36.0" , "sass-loader" : "8.0.2" , "svg-sprite-loader" : "^6.0.11" , "svgo-loader" : "^2.2.1" , "typescript" : "4.1.6" , "vue-template-compiler" : "2.6.14" } }
安装完之后,我们需要配置 vue.config.js
文件
1 2 3 + .use ('svgo-loader' ).loader ('svgo-loader' ) + .tap (options => ({...options, plugins : [{removeAttrs : {attrs : 'fill' }}]})) + .end ()
完整的 vue.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 module .exports = { lintOnSave : false }const path = require ('path' )module .exports = { lintOnSave : false , chainWebpack : config => { const dir = path.resolve (__dirname, 'src/assets/icons' ) config.module .rule ('svg-sprite' ) .test (/\.svg$/ ) .include .add (dir).end () .use ('svg-sprite-loader' ).loader ('svg-sprite-loader' ).options ({extract :false }).end () .use ('svgo-loader' ).loader ('svgo-loader' ) .tap (options => ({...options, plugins : [{removeAttrs : {attrs : 'fill' }}]})) .end () config.plugin ('svg-sprite' ).use (require ('svg-sprite-loader/plugin' ), [{plainSprite : true }]) config.module .rule ('svg' ).exclude .add (dir) } }
收工,效果如下
PS: vue.config.js
报 eslint
错误怎么办?
把这句话添加到 vue.config.js
的第一行即可