最新方法:使用
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
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的一个模块,可以用来做path
module.exports = {
lintOnSave: false,
//2.添加chainWebpack
chainWebpack: config => {
const dir = path.resolve(__dirname, 'src/assets/icons')
//配置loader
config.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
},
},