Vue项目引入使用svg

Vue项目引入使用svg

随着项目页面的增多,UI 库的 svg 图标渐渐不够用了。于是 UI 给了一大堆的 svg 新的图标,一个个引入显然不实际,于是把 svg 放到指定文件夹,然后批量引入,通过组件去使用这一堆 svg。

项目结构

|--build
|   `-- webpack.base.js
`--src
    `-- assets
        `-- icons
            |-- index.js
            `-- svg
                `-- 全部的svg图标 `xxx.svg`

大概目录结构如下,因为是自己写的 webpack 配置,等下也会说 vue.config.js 该如何改造
所有的 svg 图标都在 assets/icons/svg 文件夹下。assets/icons/index.js 就是我们的引入的入口文件了

动态引入所有的 svg

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

requireAll(req)

index.js 的文件就是为了引入 ./svg 目录下的所有 .svg 文件,使用 requireAll 引入,就无须手动一个个引入了

创建组件,使用 svg

刚才的 svg 资源是在 assets 目录下的,接下来是新建组件,所以在 src/components 目录下,新建一个 SvgIcon.vue 的组件

  • src/components/SvgIcon.vue
<template>
  <svg class="svg-icon" aria-hidden="true" v-if="iconName">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
import '../assets/icons/index'
export default {
  name: 'SvgIcon',
  props: {
    name: {
      default: '',
      type: String
    }
  },
  computed: {
    iconName() {
      let name = this.name
      if (name) {
        return `#icon-${name}`
      } else {
        return '#icon-icon'
      }
    }
  }
}
</script>

留意看第 8 行的代码,引入对应的 js 文件。所以我们在注册组件时,自动会引入对应的 icon

留意 21 行的 #icon-${name} 稍后会解释到。

修改 webpack 配置

组件已经准备好了,可是 webpack 只认得 js 文件,所以我们还得找到对应支持 svg 的插件 svg-sprite-loader

npm i svg-sprite-loader -D

项目的 webpack 配置

如果是自定义的 webpack 配置,找到 module.rules 添加一项处理 svg:

  • webpack.config.js

svgoConfig 是我项目自定义的内容,仅供参考,按需选配

其次,如果配置的 svg 与其他库有冲突(比如 iview),所以就配置只指定 /src/assets/icons 做转换,其余的都留给 url-loader 处理

既然 svg-sprite-loader 已经处理了指定的文件夹,那么 url-loader 就无须重复处理了 (这部分的配置理解为主,功能效果是一致的)

如此一来,既可以处理项目原有的 svg 不受影响,新添加的 svg-icon 也有插件进行处理了。

var svgoConfig = JSON.stringify({
    
    
  plugins: [
    {
    
     removeTitle: true },
    {
    
     convertColors: {
    
     shorthex: true } },
    {
    
     convertPathData: true },
    {
    
     cleanupAttrs: true },
    {
    
     removeComments: true },
    {
    
     removeDesc: true },
    {
    
     removeUselessDefs: true },
    {
    
     removeEmptyAttrs: true },
    {
    
     removeHiddenElems: true },
    {
    
     removeEmptyText: true }
  ]
})

module: {
    
    
  rules: [
    {
    
    
      test: /.*\.svg$/,
      loaders: [
        {
    
    
          loader: 'svg-sprite-loader',
          options: {
    
    
            symbolId: 'icon-[name]'
          }
        },
        'svgo-loader?' + svgoConfig
      ],
      include: [
        // 处理不了 iview 的字体,所以只处理本地svg
        resolve('/src/assets/icons')
      ]
    },

    {
    
    
      test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
      loader: 'url-loader',
      options: {
    
    
        publicPath: '../../',
        limit: 10000,
        name: utils.assetsPath('fonts/[name].[ext]?[hash:7]')
      },
      exclude: [resolve('/src/assets/icons')] // 已经交由 svg-sprite-loader 处理,就排除指定文件夹
    }
  ]
}

vue-cli 配置

vue-cli 配置文档

同理,vue-cli 默认有处理 svg 的插件,所以先把 src/assets/icons 的排除

然后在经过 svg-sprite-loader 来配置处理图标

module.exports = {
    
    
  chainWebpack(config) {
    
    
    config.module
      .rule('svg')
      .exclude.add(resolve('src/assets/icons'))
      .end()
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/assets/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
    
    
        symbolId: 'icon-[name]'
      })
      .end()
  }
}

icon-name 的玄机

可以看到无论是 webpack 配置还是 vue-cli 配置,在 options.symbolId 都有一段 icon-[name] 的配置。这段也是我们组件识别到底使用哪个 svg 的关键,所以这里的 icon- 需要和组件返回的 #icon-${name} 格式一致。

如果不想叫 icon-xxx 那么改动的话记得组件和 webpack 配置都得同步修改即可。

使用 svg 组件

引入组件的步骤就不写了。用法如下:

example 就是 svg 的文件名称,文件如下: assets/icons/svg/example.svg

<svg-icon name="example" />

这样就可以愉快的使用自定义的 svg 了。

猜你喜欢

转载自blog.csdn.net/Jioho_chen/article/details/115284175