How to use icons elegantly in Vue projects

Before starting to understand how to use icons in Vue projects, we need to understand some of the most basic knowledge points of icons - sprite technology.

Sprite technology

Currently, the best practice for SVG sprites is to use symbol elements. What is the symbol element? Simply translated, it means "symbol". However, this interpretation does not fit the scene here. I don't know if you have used Flash, symbol is actually similar to "movie clip" or "component" in Flash. Therefore, I personally think that symbol should be interpreted as "component" most appropriately! So, what is the relationship between symbol and SVG Sprite? We can regard SVG elements as a stage, and symbols are assembled components on the stage one by one. These one by one components are the SVG icons we will use one by one.
Thus, the code structure for an SVG element that combines three SVG icons would be as follows:

<svg>
    <symbol>
        <!-- 第1个图标路径形状之类代码 -->
    </symbol>
    <symbol>
        <!-- 第2个图标路径形状之类代码 -->
    </symbol>
    <symbol>
        <!-- 第3个图标路径形状之类代码 -->
    </symbol>
</svg>

Each symbol is an icon element, but only the above code cannot render anything.
Because a symbol element itself is not rendered, only the instance of the symbol element (a reference to the symbol element) to render.

symbol is like a piece of clothing, no one wears it I don't know how the upper body effect will be.

The use element is a very powerful and important element in SVG, especially in web development:

  • can be called repeatedly;
  • Call across SVG;

1. Can be called repeatedly

During the development, you finally used a lot of coordinate values ​​to draw a graph. What would you do if you made the same graph again? Copy the code again? Everyone who learns programming knows a truth, we need to encapsulate things that are called repeatedly, but in SVG we don’t need to encapsulate, just repeat directly Just do:

<svg>
  <symbol>
    <g id="shape">
        <rect x="0" y="0" width="50" height="50" />
        <circle cx="0" cy="0" r="50" />
    </g>javascript:;
  </symbol>

  <use xlink:href="#shape" x="50" y="50" />
  <use xlink:href="#shape" x="200" y="50" />
</svg>

The same symbol, but the x-axis distance is slightly different when calling, we can directly use Just adjust.
First of all, notice that there is no use element to find the element to use through the xlink:href attribute. #shape corresponds to the element whose id is shape. The use element can have its own coordinates, support transform transformation, and even use other use elements.
Here, the two use elements use the same symbol element (combination), thus realizing the repeated calling function of graphics.
2. Cross-SVG call
The use element in SVG can call the elements of other SVG files, as long as it is in one document (HTML).
Assuming that the element whose id is shape in the above example is in the same HTML as the following example, it can be used as well:

<svg width="500" height="110">
    <use xlink:href="#shape" x="50" y="50" />
</svg>

And this cross-SVG call is the core of "SVG Sprite Technology".
Just imagine, we only need to load an SVG file full of Sprite (symbol) somewhere on the page (or directly include the SVG code), so, in any corner of the page, as long as we want to use this icon, we only need a simple code , icon size CSS control, there is only one use element with only xlink:href attribute, Done! Finished! That is to say, at the HTML level, the code cost of icons is almost the same as that of traditional CSS Sprite or popular font-face. The code is concise and easy to maintain. All SVG icons are on one SVG source. The size can be stretched arbitrarily, and the color can be controlled. It is really the future star of Web icons.

How to use Sprite technology in Vue project

Appeal We understand the basic principle of Sprite technology, nothing more than importing iconfont.js (including all generated symbols, an svg code generated with js) and then it can be used directly. But there is a shortcoming, which is that it is not intuitive enough. After all, no one can directly see what the icon they introduced from the code, nor do they know which icon name the required icon corresponds to. Every time they use it, they have to check the documentation. And when adding, deleting or modifying icons, new js has to be generated to replace the original iconfont.js.

So in the Vue project, we can use svg-sprite-loader, which is a webpack loader. In fact, any project compiled with webpack can use this plugin. It can package multiple SVG images into svg-sprite.

First, we install it in our Vue project:

npm install svg-sprite-loader -D 或 yarn add svg-sprite-loader -D

Then create a folder:
Create a folder under the src directory, mainly to store the svg image files to be used, such as src/svg

Configure webpackConfig:
Now that svg-sprite-loader is installed, you need to configure webpack to use it

1. For Vue CLI3.0 and above, we mainly use vue.config.js for webpack configuration:

module.exports = {
  chainWebpack: config => {
    // 清空默认svg规则
    config.module
      .rule('svg')
      .uses.clear()
    config.module //针对svg文件添加svg-sprite-loader规则
      .rule('svg1')
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()
  }
}

or

module.exports = {
  chainWebpack: config => {
    // svg rule loader
    const svgRule = config.module.rule('svg') // 找到svg-loader
    svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
    svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
    svgRule // 添加svg新的loader处理
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]',
      })
    // 修改images loader 添加svg处理
    const imagesRule = config.module.rule('images')
    imagesRule.exclude.add(resolve('src/assets/icons'))
    config.module
      .rule('images')
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
  }
}

2. For Vue projects built with old scaffolding, such as hyper-converged projects, we configure them in src/build/webpack.base.conf.js:

module: {
    rules: [
      {
        test: /\.svg$/,
        loader: 'svg-sprite-loader',
        include: [resolve('src/svg')],
        options: {
          symbolId: 'icon-[name]'
        }
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        exclude: [resolve('src/svg')], // 去除默认图片处理对指定 svg 的影响
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      }
    ]
  }

import automatically

When we put the icons to be used into the folder created in the appeal operation, we also need to use the require.context of webpack to import these icon files.

require.context(directory,useSubdirectories,regExp):

  • directory: Indicates the directory to be retrieved
  • useSubdirectories: Whether to retrieve subdirectories
  • regExp: regular expression to match files

require.context("./test", false, /.test.js$/); This line of code will go to the test
folder (not including subdirectories) to find all files whose file names end with .test.js Files that can be required. To put it more bluntly,
we can introduce the corresponding file modules through regular matching.

Add the following code to main.js:

const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)

Afterwards, we can directly add, delete, and modify the icons in the svg folder. No matter what, the svg symbol will be automatically generated.
At this point we can use the icon directly in the project:

<svg><use xlink:href="#icon-name"/></svg>

But we can encapsulate it into a standard Vue component:

<template>
  <svg :class="className" aria-hidden="true">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true,
    },
    className: { // 自定义 svg 类名,后期可根据类名修改 svg 样式
      type: String,
      default: '',
    },
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`; // 拼接成设置好的 id 名格式
    }
  },
};
</script>

<style lang="less" scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

In this way, we are done, and we can use SVG files directly in the Vue project as we like.

Guess you like

Origin blog.csdn.net/weixin_43589827/article/details/115672361