A
A
antimodern2019-02-17 20:17:04
Vue.js
antimodern, 2019-02-17 20:17:04

Best way to make an SVG icon system?

Actually, I was going to put things in order, and do something like There are a lot of ways to do it (I counted 7 pieces). I stopped at 2 (with the prospect of adding animation, etc.): 1. Stupidly in the forehead:
<app-icon name="heart" />

<template>
  <div>
    <svg v-if="name ==='heart'">
      ...
    </svg>
    <svg v-else-if="name ==='like'">
      ...
    </svg>
    ...
  </div>
</template>

QUESTION: will there be a duplication of the amount of code downloaded to the client (using the standard webpack starter, for example)? Those. the same very large component (let's say there are 200 icons with v-if in one component) is used many times in the application. Everything will be reloaded, or is webpack somehow optimizing this?
2. Use sprites: make one sprite component with symbols, load it in the project root once, and make an Icon.vue component in which the same v-if only uses use for the sprite.
3. Your option and why so? (don't send me a link to Sarah Drasner, I don't like this method)

Answer the question

In order to leave comments, you need to log in

3 answer(s)
S
Sergey delphinpro, 2019-02-17
@antimodern

In my opinion, the best option is the one that is widely used - each icon is a separate component.

<app-icon-heart/>
<app-icon-like/>

Sprites are hardly needed here. The code is already going into a single bundle.

N
nvdfxx, 2019-02-18
@nvdfxx

<template>
    <svg :src=`../assets/icons/${name}.svg`></svg>
</template>

<script>
export default {
    props: {
        name: {
            type: String,
            required: true
        }
    }
}
</script>

And call this component for example like this , webpack, I think it will cope with such a task <v-icon name="like"/>

D
dest86, 2019-02-20
@dest86

svg-sprite-loader
Setting up the loader

// vue.config.js
module.exports = {
   ...

    chainWebpack: config => {
      const Sprite = config.module.rule('svg-sprite')
    
      Sprite
        .test(/\.(svg)(\?.*)?$/)
        .include
         // указываем путь к папке с иконками что бы не было конфликтов(например со шрифтами)
          .add(path.resolve(__dirname,'src/assets/icons'))
        .end()                   
        .use('file-loader')
          .loader('file-loader')
          .options( {
            name: 'static/img/[name].[hash:8].[ext]'
          })              
        
      Sprite
        .use('file-loader')
        .loader('svg-sprite-loader')
  
    }
}

Creating an Icon Component
<template>
  <svg :class="className" xmlns="http://www.w3.org/2000/svg" :style="style" v-on="$listeners">
    <use :xlink:href="`#${name}`" xmlns:xlink="http://www.w3.org/1999/xlink"/>
  </svg>
</template>

<script>
export default {
  name: 'svg-icon',

  props: {
    name: {
      type: String,
      required: true
    },
    width: {
      type: Number,  
    },
    height: {
      type: Number,   
    }
  },
  mounted() {
    require(`@/assets/icons/${this.name}.svg`).default.url;
    
  },
  updated() {
    // у меня возникали проблемы с тем что иконки не всегда отображаются, поэтому продублировал запрос к иконке  
    require(`@/assets/icons/${this.name}.svg`).default.url;
  },
  computed: {

    className() {
      return 'svg-icon svg-icon--' + this.name;
    },
    style() {
      let style = {}
      if (this.width) {
        style.width = this.width+'px';
      }
      if (this.height) {
        style.height = this.height+'px';
      }
      return style;       
    }

  }
};
</script>

<style>
  .svg-icon {
    fill: currentColor;
    height: 24px;
    width: 24px;
    stroke: none;
  }
</style>

icon call Accordingly, the svgicon component is either connected in each component or globally
//main.js
//....
import SvgIcon from '@/components/SvgIcon

//....
Vue.use(SvgIcon, {
  tagName: 'svgicon'
})

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question