在vue中使用svg(通过组件)

1,841 阅读1分钟
  1. 安装解析svg类型图标的依赖

image.png

npm install svg-sprite-loader --save-dev
npm install svgo --save-dev  // 一个用于优化SVG文件的Node.js工具

很多网上下载或者导出的SVG文件中会有很多冗余无用的信息,可以通过svgo插件对它进行优化。无用的信息有:编辑器源信息,注释,以及其它一些不会影响渲染效果但可以去除的信息等。该svgo具有基于插件的体系结构,因此几乎每个优化都是一个单独的插件。

  1. 在 src 目录下新建 src/icons/svg 目录,存放项目所使用的所有图标 svg 文件

image.png

  1. 在 vue-config.js 中添加配置:
module.exports = {
  chainWebpack(config) {
     //配置svg
      config.module
        .rule('svg')
        .exclude.add(resolve('src/icons'))
        .end()
      config.module
        .rule('icons')
        .test(/\.svg$/)
        .include.add(resolve('src/icons')) //处理svg目录(根据你建的文件路径)
     // .include.add(resolve('src/icons')).add(resolve('src/assets'))
        .end()
        .use('svg-sprite-loader')
        .loader('svg-sprite-loader')
        .options({
          symbolId: 'icon-[name]'
        })
        .end()
  },
// .include.add(resolve('src/icons')).add(resolve('src/assets'))
配置中这行代码是用来处理包含svg文件的目录,我在原基础上添加了asset文件夹
所以如果想正常直接使用svg文件,需要将其放置在除了'src/icons'、'src/assets'下的其他目录
然后在代码直接引入即可
<img src='./attack_chain_icon1.svg'>
  1. 创建组件 components/SvgIcon.vue
<template>
  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" ></div>
  <svg v-else :class="svgClass" aria-hidden="true">
    <use :xlink:href="iconName" />
  </svg>
</template>
 
<script>
import { isExternal } from '@/utils/validate'
import '@/icons'
 
export default {
  name: 'svg-icon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    isExternal() {
      return isExternal(this.iconClass)
    },
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    },
    styleExternalIcon() {
      return {
        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
      }
    }
  }
}
</script>
 
<style scoped>
.svg-icon {
  /* width: 1rem;
  height: 1rem; */
  vertical-align: middle;
  fill: currentColor;
  overflow: hidden;
}
 
.svg-external-icon {
  background-color: currentColor;
  mask-size: cover!important;
  display: inline-block;
}
</style>

isExternal方法及作用

/**校验传入的iconClass是否为外部链接
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path) {
  return /^(https?:|mailto:|tel:)/.test(path);
}
  1. 在 src/icons 目录下新建 index.js文件、svgo.yml文件

image.png

index.js中

import Vue from 'vue';
import SvgIcon from '@/components/SvgIcon'; // svg component
 
// register globally
Vue.component('svg-icon', SvgIcon);
 
const requireAll = requireContext => requireContext.keys().map(requireContext);
const req = require.context('./svg', false, /\.svg$/);
requireAll(req);

如果项目图标文件较多,可以对 icons 目录做详细的划分,然后修改上述 index.js

svgo.yml中(基于svgo对svg文件进行压缩)

# replace default config
# multipass: true
# full: true
 
plugins:
 
  # - name
  #
  # or:
  # - name: false
  # - name: true
  #
  # or:
  # - name:
  #     param1: 1
  #     param2: 2
 
- removeAttrs:
    attrs:
      - 'fill'
      - 'fill-rule'

配置package.json文件

image.png

"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"

当初始化使用或者新增svg图标时,需要执行以下代码

npm run svgo
  1. 在 main.js 入口文件中 全局引入 icons
import "./icons";
  1. 使用svg组件
 <svg-icon icon-class="svgName" class="icon" />
//svgName为.svg后缀前的文件名

实际开发中应用场景如:

<div v-for="item in attackChainList" :key="item.stage" class="chain-item">
    <svg-icon :icon-class="item.icon" alt="" class="attack-chain" />
    <div>{{ item.stage }}</div>
</div>

attackChainList: [
  { icon: 'attack_chain_icon1', stage: '观察' },
  { icon: 'attack_chain_icon2', stage: '实践' },
  { icon: 'attack_chain_icon3', stage: '总结' }
]

.attack-chain {
    width: 82px;
    height: 77px;
    margin-right: 12px;
}

参考文章:blog.csdn.net/m0_65835778…