若依封装的svg-icon组件加载问题

864 阅读3分钟

前提需求:目前项目中有菜单管理,需增加icon属性,但是当把注册文件和具体的组件都写好,依旧不能出现组件图标,由此展开

结论!!!

需再vue.config文件中配置loader,并且需要下载 svg-sprite-loader 详情看最后

若依的文档 svg-icon

若依的文档 svg-icon地址

全局 Svg Icon 图标组件

默认在 @/icons/index.js (opens new window)中注册到全局中,可以在项目中任意地方使用。所以图标均可在 @/icons/svg (opens new window)。可自行添加或者删除图标,所以图标都会被自动导入,无需手动操作。

本项目中

在assets/icons/index.js中

import Vue from 'vue' 
import SvgIcon from '@/components/SvgIcon'// svg component // register globally 

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

requireAll(req)

在components/SvgIon中

<template>
  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
import { isExternal } from '@/util/validate'

export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  mounted(){
   
  },
  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: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
  
}

.svg-external-icon {
  background-color: currentColor;
  mask-size: cover!important;
  display: inline-block;
}
</style>

具体位置

image.png

页面代码

image.png

页面效果

image.png

以上两个文件集成写好,还不足以实现组件加载!!!!

注意!!!!

vue.config文件中,还需要注册loader

增加一下代码,并且需要下载 svg-sprite-loader

svg-sprite-loader

image.png

const path = require('path')

function resolve(dir) {
  return path.join(__dirname, dir)
}

const { defineConfig } = require('@vue/cli-service')
const proxyTarget = require('./_proxyTarget')
module.exports = defineConfig({
  transpileDependencies: true,
  // 删除eslint 警告
  lintOnSave: false,
  // 设置打包之后读取js、 css文件,以相对地址为基准
  publicPath: './',
  configureWebpack: {
    externals: {
      "BMapGL": "BMapGL",
  },
  },
  devServer: {
    open: true, // 配置自动启动浏览器
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    proxy: {
      '/': {
        target: proxyTarget,
        ws: false, // 需要websocket 开启
        changeOrigin: true,
      }, 
    }
  },
  chainWebpack(config) {
    config.plugins.delete('preload') // TODO: need test
    config.plugins.delete('prefetch') // TODO: need test

    // set svg-sprite-loader
    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()

    config.when(process.env.NODE_ENV !== 'development', config => {
          config
            .plugin('ScriptExtHtmlWebpackPlugin')
            .after('html')
            .use('script-ext-html-webpack-plugin', [{
            // `runtime` must same as runtimeChunk name. default is `runtime`
              inline: /runtime\..*\.js$/
            }])
            .end()

          config.optimization.splitChunks({
            chunks: 'all',
            cacheGroups: {
              libs: {
                name: 'chunk-libs',
                test: /[\\/]node_modules[\\/]/,
                priority: 10,
                chunks: 'initial' // only package third parties that are initially dependent
              },
              elementUI: {
                name: 'chunk-elementUI', // split elementUI into a single package
                test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
                priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
              },
              commons: {
                name: 'chunk-commons',
                test: resolve('src/components'), // can customize your rules
                minChunks: 3, //  minimum common number
                priority: 5,
                reuseExistingChunk: true
              }
            }
          })

          config.optimization.runtimeChunk('single'),
          {
             from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
             to: './' //到根目录下
          }
    })
  }
})

chainWebpack 是在Webpack的配置文件中通过chainWebpack方法对Webpack配置进行链式操作,主要包括以下几个部分: 
删除预加载和预获取插件:
config.plugins.delete('preload') 
config.plugins.delete('prefetch')
删除默认的预加载(preload)和预获取(prefetch)插件。这通常是为了在生产环境中控制资源加载的方式。 

设置SVG精灵图loader: 
首先,排除对src/assets/icons目录中的SVG文件使用常规的svg loader。 然后,创建一个新的规则icons,匹配所有.svg文件,并且仅包含src/assets/icons目录下的SVG文件。 
对这个规则内的SVG文件应用svg-sprite-loader,生成SVG Sprite,并设置symbolId格式为icon-\[name]。 

针对非开发环境的优化配置: 当运行环境不是开发环境时,进行以下优化操作: 
添加ScriptExtHtmlWebpackPlugin插件以控制HTML文件中脚本标签的行为,将包含runtime关键字的JS文件内联加载。 
设置splitChunks策略,将第三方库、ElementUI框架以及至少被3个chunk共享的组件代码分别提取到单独的chunk中,以便复用这些模块。 
将runtime chunk设置为单个文件。 

处理静态资源路径: 
该段代码片段的最后一部分似乎不完整或有误,它看上去试图从public/robots.txt复制文件到根目录下,但在当前上下文中没有正确实现。
如果确实想要处理静态资源如robots.txt,通常需要使用CopyWebpackPlugin或其他类似的插件来完成这一任务。 
总结:此配置主要对Webpack进行了定制化处理,包括SVG资源的特殊处理、优化分割chunks策略、以及在生产环境下调整脚本加载行为等。对于静态资源的复制,可能需要补充相应的插件配置。

页面效果

image.png