最新方法:使用
svg-sprite-loader
引入icon
一.svg-sprite-loader
的基本使用
1.在iconfont.cn下载好需要的图标后,把它添加到项目assets
里并引入。
那如何引入呢? 🔍typescript svg cannot find module
方法:在系统文件shims-vue.d.ts
里添加如下代码
src > shims-vue.d.ts
declare module "*.svg" {const content: any;export default content;
}
components > Nav.vue
<script lang="ts">import icon1 from "@/assets/icons/money.svg";import icon2 from "@/assets/icons/labels.svg";import icon3 from "@/assets/icons/statistics.svg";
//console.log(icon1); /img/label.4b53fd4c.vue
</script>
但是最后得到的是字符串,不符合我们的需求,怎么办?
我们需要一个loader,叫做svg-sprite-loader
svg-sprite-loader文档
2.使用方法:
(1)安装
yarn add svg-sprite-loader -D
(2)添加配置
根据文档的配置要求,需要在webpack.config.js
里添加配置。但由于我们的项目里没有这个文件,只有vue.config.js
,所以需要按照vue-cli
的文档将下面这段内容翻译成我们需要的内容。
// webpack 1 multiple loaders
{test: /\.svg$/,loaders: [`svg-sprite-loader?${JSON.stringify({ ... })}`,'svg-transform-loader','svgo-loader']
}
在vue.config.js中添加翻译后的代码:
src > vue.config.js
const path = require('path') //1.引入nodejs的一个模块,可以用来做pathmodule.exports = {lintOnSave: false,
//2.添加chainWebpackchainWebpack: config => {const dir = path.resolve(__dirname, 'src/assets/icons')//配置loaderconfig.module //config是vue把webpack的api给封装后暴露给我们的一个对象.rule('svg-sprite') //添加一个规则,叫做svg-sprite.test(/\.svg$/) //这个规则的特点:如果能匹配上这个正则就用这个规则(以.svg结尾的).include.add(dir).end() // 只包含icons目录,其它目录一概不走这个规则 .use('svg-sprite-loader').loader('svg-sprite-loader').options({ extract: false }).end() //使用这个loader(已安装),然后添加一个选项:不要把它解析出文件来,我不需要文件//配置插件config.plugin('svg-sprite').use(require('svg-sprite-loader/plugin'), [{ plainSprite: true }]) // 使用的路径是..., 添加一个选项config.module.rule('svg').exclude.add(dir) //其他svg loader排除icons目录,防止冲突}
}
control+c
重启服务器后,我们的body就会创建一个svg标签,这个标签内有很多symbol,每个symbol都有id
,并用id作为识别。这时候只要我们import了就可以使用<svg><use xlink:href="#id" /></svg>
展示图标。
3.使用symbol
Nav.vue
<template><div class="nav"><router-link to="/money"><svg><use xlink:href="#money" /></svg> 记账</router-link>|<router-link to="/labels"><svg><use xlink:href="#labels" /></svg> 标签</router-link>|<router-link to="/statistics"><svg><use xlink:href="#statistics" /></svg> 统计</router-link></div>
</template>
二.优化
1.每个icon都要import
太麻烦,能不能直接引入icons文件
?
2.这串代码<svg><use xlink:href="#id" /></svg>
,能不能也封装成一个组件?
1.如何import一个目录?
components > Nav.vue
<script lang="ts">
// import icon1 from "@/assets/icons/money.svg";
// import icon2 from "@/assets/icons/labels.svg";
// import icon3 from "@/assets/icons/statistics.svg";let importAll = (requireContext: __WebpackModuleApi.RequireContext) =>requireContext.keys().forEach(requireContext);
try { //指定要搜索的路径importAll(require.context("../assets/icons", true, /\.svg$/));
} catch (error) {console.log(error);
}
</script>
这段代码就可以实现将一个目录里面任意后缀的文件,统一全部引入到当前文件。
2.封装icon组件
(1)新建组件Icon.vue
,代码如下:
components > Icon.vue
<template><div><svg class="icon"><use :xlink:href="'#' + name" /> </svg></div>
</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); }export default {name: "Icon",props: ["name"], //添加外部属性
};
</script>
(2)使用组件
components > Nav.vue
<template><div class="nav"><router-link to="/money">//<svg><use xlink:href="#money" /></svg> <Icon name="money" />记账</router-link>|<router-link to="/labels"><Icon name="labels" />标签</router-link>|<router-link to="/statistics"><Icon name="statistics" />统计</router-link></div>
</template>
<script lang="ts">
export default { name: "Nav"};
</script>
main.ts //入口文件
import Icon from "@/components/Icon.vue";
Vue.component("Icon", Icon);
三.解决报错
(1)🔍eslint报错如何解决?
git commit提交代码时报错
error: Require statement not part of import statement
在文件最上面添加eslint-disable
,意思是不要提示。
src > vue.config.js
/* eslint-disable */
(2)error: '__WebpackModuleApi' is not defined
解决方法: 在.eslintrc.js
文件中的rules内添加相关代码,注册后可能还会报错,但不影响我们使用,能够正常commit。
.eslintrc.js
rules: {'globals': {"__WebpackModuleApi": true},
},