svg做图标自动引入和生成

说明

传统方案中,是使用图标生成字体,然后当图标发生变化的时候需要手动的每次去替换,其实可以通过svg-sprite-loader,可以实现增加svg的时候自动加载图标。
npm i svg-sprite-loader

探索

整体思路:原来的svg排除一个目录,并增加一个配置

小知识点:

  1. module.exports = {
  2. chainWebpack(config){
  3. // 在已有的svg loader配置中 排除掉对src/icons里svg进行转换
  4. config.module
  5. .rule('svg')
  6. .exclude.add(resolve('src/icons')) // 排除掉src/icons目录
  7. .end()
  8. // svg icon工作原理 https://segmentfault.com/a/1190000015367490
  9. // 配置svg-sprite-loader
  10. config.module
  11. .rule('icons')
  12. .test(/\.svg$/)
  13. .include.add(resolve('src/icons')) // 指定src/icons要处理svg的文件目录
  14. .end()
  15. .use('svg-sprite-loader')
  16. .loader('svg-sprite-loader') // 用svg-sprite-loader解析
  17. .options({
  18. symbolId: 'icon-[name]' // symbol id命名格式 icon-图标名称
  19. })
  20. .end()
  21. }
  22. }
  23. //使用
  24. <svg>
  25. <use xlink:href="#icon-qq">
  26. </svg>
  27. import 'icons/svg/qq.svg'

优化

自动引入:用req指定上下文,然后入口文件进行全量的自动引入该目录下所有图片。

疑问点:全量引入会不会很大?

  • svg本身都是文本信息,体积比图片小
  • 如果实际业务中,对对应图片的使用是部分的,你可以去单独定义按照划分的svg目录,然后按需引入
  • 维护的方式是通过按需使用的,如果不需要使用,直接删除;需要新的,进行新增。
  1. //只匹配到当前上下文,不包括子目录,定义匹配的正则文件
  2. const req = require.contex('./svg',false,/\.svg$/);
  3. req.keys().map(req);
  4. //main.js中加载 从而实现全量自动加载所有图标
  5. import 'icons/index.js';

定义svg的使用组件,让使用更加方便,你可以通过传入属性控制其加载的图片文件夹,具体样式等等

  1. //定义一个svgIcon 的组件,然后全局使用
  2. import 'components/svgIcon'
  3. Vue.component('svg-icon',svgIcon)

Nuxt框架配置Svg自动导入

1. 引入解析器插件

https://www.npmjs.com/package/nuxt-svg-sprite-loader
nuxt.config.js

  1. export default {
  2. ...
  3. modules: [
  4. ['nuxt-svg-sprite-loader', {
  5. symbolId: 'foo-[name]'
  6. }]
  7. ]
  8. }

2. 编写插件plugins,全局引入组件

编写组建components/SvgIcon/icon.vue

  1. <template>
  2. <!-- 如果iconClass是带协议的图标链接 则通过style属性方式渲染-->
  3. <div
  4. v-if="isExt"
  5. class="svg-icon svg-external-icon"
  6. :style="styleExternalIcon"
  7. v-bind="$attrs"
  8. />
  9. <!-- SVG icon 通过名称使用 -->
  10. <svg v-else :class="svgClass" aria-hidden="true" v-bind="$attrs">
  11. <!--
  12. SVG中的use元素可以调用其他SVG文件的元素,<use xlink:href="#symbolId"></use>
  13. -->
  14. <use :xlink:href="iconName" />
  15. </svg>
  16. </template>
  17. <script>
  18. import { isExternal } from '@/common/utils'
  19. /**
  20. * v-bind="$attrs" 组件$attrs属性透传绑定到元素上
  21. * vue3.0中$lietens已被移除 现在事件监听器是 $attrs 的一部分
  22. * 文档说明:
  23. * https://v3.cn.vuejs.org/guide/migration/listeners-removed.html#_3-x-%E8%AF%AD%E6%B3%95
  24. */
  25. export default {
  26. name: 'SvgIcon',
  27. inheritAttrs: false, // 组件上的$attrs不自动添加到组件根元素上 默认添加到组件根元素上
  28. props: {
  29. iconClass: {
  30. type: String,
  31. default: ''
  32. },
  33. className: { // 我们也可以自定义类名
  34. type: String,
  35. default: ''
  36. }
  37. },
  38. data () {
  39. return {
  40. isExt: '',
  41. iconName: '',
  42. svgClass: '',
  43. styleExternalIcon: ''
  44. }
  45. },
  46. created () {
  47. const that = this
  48. // 是否是带协议的图片链接
  49. this.isExt = isExternal(this.iconClass || '')
  50. // 拼接成symbolId 在loader配置中指定了symbolId格式 icon-图标名称
  51. this.iconName = `#icon-${that.iconClass}`
  52. // 添加类名 props.className外部传入自定义类名
  53. this.svgClass = that.className ? `svg-icon ${that.className}` : 'svg-icon'
  54. // 如果iconClass是带协议的图标链接 则通过style css属性方式渲染
  55. this.styleExternalIcon = {
  56. mask: `url(${that.iconClass}) no-repeat 50% 50%`,
  57. '-webkit-mask': `url(${that.iconClass}) no-repeat 50% 50%`
  58. }
  59. }
  60. }
  61. </script>
  62. <style scoped>
  63. .svg-icon {
  64. width: 1em;
  65. height: 1em;
  66. vertical-align: -0.15em;
  67. fill: currentColor;
  68. overflow: hidden;
  69. }
  70. .svg-external-icon {
  71. background-color: currentColor;
  72. mask-size: cover !important;
  73. display: inline-block;
  74. }
  75. </style>

plugins/svgIcon

  1. // plugins目录
  2. import Vue from 'vue'
  3. import SvgIcon from '@/components/svgIcon/icon.vue'
  4. const req = require.context('../icons/svg', false, /\.svg$/)
  5. req.keys().map(req)
  6. Vue.component('svg-icon', SvgIcon)

在nuxt.config.js的配置项plugins中引入

  1. plugins: [
  2. '@/plugins/svgIcon'
  3. ],

引入阿里图标

在nuxt中,需要在plugins引入kyyIcon

  1. import Icon from 'ant-design-vue/lib/icon'
  2. import Vue from 'vue'
  3. const IconFont = Icon.createFromIconfontCN({
  4. scriptUrl: '//at.alicdn.com/t/font_1400982_c4hpndz7xd.js'
  5. })
  6. Vue.component('KyyIcon', IconFont)
  7. const CgsIconFont = Icon.createFromIconfontCN({
  8. scriptUrl: '//at.alicdn.com/t/font_2233276_hvbjqskdw5i.js'
  9. })
  10. Vue.component('CgsIcon', CgsIconFont)

去iconfont图库复制路径

image.png

存在问题

图标组件无法自定义长宽高及颜色