Vue 加载 svg icon

2021-05-27  本文已影响0人  随机昵称

我们都知道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 等插件方式加载;

image
const context = require.context(".", false, /\.svg$/);
const requireAll = (requireContext) => {
  return requireContext.keys().map(requireContext);
};
requireAll(context);

webpack 关于 require.context 的解释,可以看一下;
我就不解释了,水平有限,还是看官方文档吧;

配置要分两种情况,看工程是用 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 下查看默认配置

webpack base rules.PNG
可以看到,默认处理 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

在需要使用 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

上一篇下一篇

猜你喜欢

热点阅读