Vue 加载 svg icon
我们都知道SVG替代图片作为图标的好处,但如何能够方便的加载在VUE工程中呢;通过直接插入SVG代码方式画,当然是OK的,但这种方式是不是很LOW,一个两个还好,如果icon太多了,那就不好管理了;
咋样才能更加友好便捷使用呢,这两天研究 2 种方式,原理都是提前加载 svg 模板到 body 中,然后在需要用到的 svg icon 的地方,用 use 标记去实例化对应的 svg ;见:http://know.webhek.com/svg/svg-symbol.html;
使用icon font等CDN方式在线加载:
好处是不用下载到本地,不用管理svg文件,方便那是真的;
坏处就是如果我们需要 icon fillColor 根据 currentColor 更改而更改的话,就不好使了,因为通常来将,加载的 svg 都是有 fillColor 的,此时在引用的地方,使用 fill color 是无效的,如下图;所以可能需要准备多套资源,增加工作量,且资源多了也会对内存和加载速度有影响;当然也可以准备不带 fill 的资源,iconfont 官网说明里给了一个不带fill的链接,我自己反正是不知道怎么弄到 iconfont 上去;
image使用svg-sprite-loader等插件本地加载
好处当然是可以定制啦,多色也没问题,只是可能需要打开文件,去掉部分 fill 属性;这样在外面传入的 fill 才能生效;
坏处当然是要本地维护这些资源了,而且需要搞定一些配置,才能快乐使用,这配置是真的没那么简单,这个后面我会讲到;
下面我就讲讲如何使用吧
1、使用 iconfont 等 CDN 链接方式加载模板;
前面说了,这个是真的简单方便
首先,默认在 iconfont 上的账户有资源啦;选择 Symbol,复制链接加到你的项目中;
image image项目 run 起来后,在 body 中可以看到加载好的模板;
image然后在需要使用的地方,插入代码
<svg class="icon"><use xlink:href="#iconzu91-copy"></use></svg>
代码中#iconzu91-copy为模板中对应的 symbol id 值;加载的效果如下:
image是不是超简单;
2、使用 svg-sprite-loader 等插件方式加载;
-
首先当然是安装插件了,
npm install svg-sprite-loader -D
-
第 2 步,下载svg 放到工程目录下,我是放在这里的,大家随意,开心就好;
-
第 3 步,批量引用 svg 文件;
在 svgicons 下新建一个 index.js,加入如下代码
const context = require.context(".", false, /\.svg$/);
const requireAll = (requireContext) => {
return requireContext.keys().map(requireContext);
};
requireAll(context);
webpack 关于 require.context 的解释,可以看一下;
我就不解释了,水平有限,还是看官方文档吧;
- 第 4 步,配置 webpack 下模块加载配置,配置的目的是要让 svg-sprite-loader 将对应的 svg 文件的模板编译加载到body中
配置要分两种情况,看工程是用 vue cli 2 还是 3 及以上创建的了;
cli2 的配置如下(cli3 的可以直接跳到 **cli3配置 **)
需要在 webpack.base.conf.js 中的 module 下的 rules 下添加如下配置
{
test: /\.svg$/,
loader: "svg-sprite-loader",
include: [resolve("src/assets/svgicons")],
options: {
symbolId: "svg-[name]"
}
}
这个意思是说,我们用 svg-sprite-loader 这个插件去加载 src/assets/svgicons 文件夹下所有的以 .svg 结尾的文件,并且模板中 symbol id 是以 svg- 开头,文件名称结尾;当然,这个前缀要不要都行;
注意,rules 中,可能还有其他的 loader 会去处理 svg 的,我们可以在对应的插件 loader 下配置exclude: [resolve("src/assets/svgicons")]
,如我这里需要配置,这样 url-loader 就不会去处理编译对应文件加下的文件了;
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: "url-loader",
exclude: [resolve("src/assets/svgicons")],
options: {
limit: 10000,
name: utils.assetsPath("img/[name].[hash:7].[ext]")
}
}
完了后,就可以run 起来,然后就可以看到 body 中已加载好了模板;
body 中 svg 模板.PNG
cli3及以上的配置如下(cli2 的可以跳过这一步)
首先在根目录新建 vue.config.js 文件,
这个地方解释一下,配置同 cli2,只不过这里看起来是没有在 cli2 中显得那么直观;
下面拆解下我自己是如何配置这部分的
首先到 node_modules/@vue/cli-service/lib/config/base.js 下查看默认配置
可以看到,默认处理 svg 文件的是 file-loader,这里我们把默认的svg的配置里加一个 exclude,同 cli2 中配置,这样 file-loader 和 我们将要设置的 svg-loader 就不会重复处理我们的src/assets/svgicons 下的 svg 文件;当然,我们也可以覆盖svg rule,这样所有的 svg 文件就会采用我们覆盖的 loader 去处理 svg 文件;
新建一个规则配置
/* eslint-disable */
const path = require("path");// @ts-ignore
/* eslint-enable */
function resolve(dir) {
// 路径可能与你的项目不同
return path.join(__dirname, dir);
}
module.exports = {
chainWebpack: (config) => {
// exclude 配置默认的 svg 规则下不处理对应我定义的文件夹下的 svg 文件
config.module.rule("svg").exclude.add(resolve("src/assets/svgicons")).end();
// 新建一个 svgIcon rule,配置它的加载方式
config.module
.rule("svgIcon")
.test(/\.svg$/)
.use("svg-sprite")
.loader("svg-sprite-loader")
.options({
symbolId: "svg-[name]",
})
.end()
.include.add(resolve("src/assets/svgicons"))
.end();
},
};
覆盖配置如下
module.exports = {
chainWebpack: (config) => {
// 先清除 uses,否则 svg 文件就会先被默认的 fileloader 处理一次,然后再被 svg-sqrite-loader 再处理一次
config.module.rule("svg").uses.clear();
config.module
.rule("svg")
.test(/\.svg$/)
.use("svg-sprite")
.loader("svg-sprite-loader")
.options({
symbolId: "svg-[name]",
})
.end()
.include.add(resolve("src/assets/svgicons"))
.end();
},
};
完了后,就可以run 起来,然后就可以看到 body 中已加载好了模板;
body 中 svg 模板.PNG
- 第 5 步,看疗效:
在需要使用 svg icon 的地方加入如下代码
<svg class="svg-icon"> <use :xlink:href="svg-svg-on-dark" /> </svg>
<svg class="svg-icon"> <use :xlink:href="svg-eye" /> </svg>
成功加载
image
后面我会再研究下 vue-svg-loader 加载 svg icon