How to use icon gracefully in Vue project

Posted by Arrow on Tue, 08 Mar 2022 00:15:35 +0100

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

Sprite Technology

Currently, SVG sprite's best practice is to use the symbol element. What is the symbol element? In simple translation, it means "symbol". However, this interpretation does not fit the scene here. I wonder if you have ever 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! What's the relationship between symbol and SVG Sprite? We can regard SVG elements as a stage, while symbol is assembled one by one on the stage. These components are SVG icons we will use one by one.
Therefore, the code structure of an SVG element with three SVG icons will be as follows:

<svg>
    <symbol>
        <!-- Code like the first icon path shape -->
    </symbol>
    <symbol>
        <!-- Code such as the second icon path shape -->
    </symbol>
    <symbol>
        <!-- Code such as the third icon path shape -->
    </symbol>
</svg>

Each symbol is an icon component, but only the above code can not present anything.
Because a symbol element itself is not rendered, there is only an instance of the symbol element (a reference to the symbol) Element).

symbol is like a dress that no one wears I don't know how the upper body works.

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

  • Repeatable call;
  • Cross SVG call;

1. Repeatable call

In the development, it's not easy for you to use a lot of coordinate values and draw a graph. What would you do if you got another same graph? Copy the code again? Everyone who learns programming knows a truth. We need to encapsulate what is called repeatedly, but in SVG, we don't need to encapsulate it, just repeat it directly On the line:

<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 use it directly Just adjust.
First, notice that the use element looks for the element to be used 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), so as to realize the function of repeated calling 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 a document (HTML).
In the following example, we can use the same element as shape:

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

This cross SVG call is the core of "SVG Sprite technology".
Imagine that we just need to load an SVG file full of Sprite(symbol) (or directly include SVG code) somewhere on the page. Therefore, in any corner of the page, as long as we want to use this icon, we can simply use this code. The icon size is controlled by CSS, and there is only a use element with xlink:href attribute, done! Done! In other words, 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 simple 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 the future star of Web icons.

How to use Sprite technology in Vue projects

On appeal, we understand the basic principle of Sprite technology, which is nothing more than the introduction of iconfont JS (including all the generated symbol s, an svg code generated with JS) and then you can use it directly. However, there is a disadvantage, which is not intuitive enough. After all, no one can directly see what the icon they introduced is like from the code, and they don't know which icon name the required icon corresponds to. They have to check the document every time they use it, and when adding, deleting and changing icons, they have to generate new JS to replace the original iconfont js.

Therefore, in Vue projects, we can use SVG sprite loader, which is a webpack loader. In fact, this plug-in can be used for any project compiled with webpack, which can package multiple SVG images into SVG sprite.

First, we install it in the Vue project:

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

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

To configure webpackConfig:
Now that SVG sprite loader is installed, you need to configure webpack to use it

1,Vue CLI3. We mainly use vue.0 and above config. JS for webpack configuration:

module.exports = {
  chainWebpack: config => {
    // Clear default svg rule
    config.module
      .rule('svg')
      .uses.clear()
    config.module //Add svg sprite loader rule for svg file
      .rule('svg1')
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()
  }
}

perhaps

module.exports = {
  chainWebpack: config => {
    // svg rule loader
    const svgRule = config.module.rule('svg') // Find SVG loader
    svgRule.uses.clear() // Clear the existing loader. If not, it will be added after this loader
    svgRule.exclude.add(/node_modules/) // Regular match exclusion node_modules directory
    svgRule // Add svg new loader processing
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]',
      })
    // Modify images loader and add svg processing
    const imagesRule = config.module.rule('images')
    imagesRule.exclude.add(resolve('src/assets/icons'))
    config.module
      .rule('images')
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
  }
}

2. In the previous Vue project of old scaffold construction, such as super fusion project, we are in Src / build / webpack base. Configuration in 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')], // Remove the influence of default image processing on the specified svg
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      }
    ]
  }

Auto import

When we put the icon to be used into the folder created in the appeal operation, we also need to use the webpack require Context 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 matching file

require.context("./test", false, /.test.js$/); This line of code will go to test
Find all file names under the folder (excluding subdirectories) test.js end of the file can be require d by the file. More frankly
We can introduce the corresponding file module through regular matching.

In main JS add the following code:

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

After that, we can add, delete and modify the icons in the svg folder directly. Don't worry about anything, and the svg symbol will be automatically generated.
At this time, we can directly use icons in the project:

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

However, we can package it into standard Vue components:

<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: { // Customize the svg class name. You can modify the svg style according to the class name later
      type: String,
      default: '',
    },
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`; //  Spliced into the set id name format
    }
  },
};
</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. We can directly use SVG files as we like in Vue projects.

Topics: Vue css svg