# Icon 组件

本项目使用vue-cli作为脚手架开发.包含了我所需要的配置: 使用 Vue + Vuex + Vue-router 作为视图层的开发.使用 TypeScript 代替 JavaScript.使用 SCSS 代替 CSS. 但是还有一些配置需要自己完成.

# SVG loader 的配置

由于使用了 TypeScript, 我们需要在声明文件(shims-vue.d.ts)里去声明一下 svg:

declare module "*.svg" {
  const content: string;
  export default content;
}
1
2
3
4

这样在引入 svg 时不会报错了.

接下来引入 svg 需要的 loaders: yarn add svg-sprite-loader svgo-loader. 然后在vue.config.js里配置:

const path = require("path");

module.exports = {
  chainWebpack: config => {
    const dir = path.resolve(__dirname, "src/assets/icons"); // 存放icons的目录

    config.module
      .rule("svg-sprite")
      .test(/\.svg$/)
      .include.add(dir)
      .end() // 包含 icons 目录
      .use("svg-sprite-loader") //使用此loader
      .loader("svg-sprite-loader")
      .options({ extract: false })
      .end()
      .use("svgo-loader")
      .loader("svgo-loader")
      .tap(options => ({
        ...options,
        plugins: [{ removeAttrs: { attrs: "fill" } }] // 删除svg的fill属性
      }))
      .end();
    config
      .plugin("svg-sprite")
      .use(require("svg-sprite-loader/plugin"), [{ plainSprite: true }]);
    config.module.rule("svg").exclude.add(dir); // 其他 svg loader 不会解析 icons 目录
  }
};
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

svg-sprite-loader的作用是解析 svg 文件, 但要注意, 如果使用 WebStorm 时, 且svg-sprite-loader的版本低于4.2.0时, 引入全局 SCSS 文件会报错(是 WebStorm code assistance analyzer 的错, 它没能解析出来). 不过在4.2.0及以上的版本中这个 bug 已被修复

svgo-loader帮助我们删除 svg 里的fill属性, 这样使得我可以自定义 svg 的颜色, 之前一旦被定好了颜色就修改不了.

# 写一个 Icon 组件

在开始写代码前, 先不要管具体的实现细节. 而是想我在使用这个 Icon 组件时的写法:

<Icon name="money" />
1

上面的形式是最简单也是最简洁的.

# 开始实现

Icon 组件的模板很容易写:

<template>
  <svg class="icon">
    <use :xlink:href="`#${name}`"></use>
  </svg>
</template>

<script lang="ts">
export default {
  name: "Icon",
  props: ["name"]
};
</script>

<style scoped>
/* iconfont推荐的默认样式 */
.icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

最主要的问题是如何一次性导入所有的 icon 到组件里以方便复用, 下面是解决代码:

const importAll = (requireContext: __WebpackModuleApi.RequireContext) =>
  requireContext.keys().forEach(requireContext);
try {
  importAll(require.context("../assets/icons", true, /\.svg$/));
} catch (e) {
  console.log(e);
}
1
2
3
4
5
6
7