vue-优雅的使用svg

vue-优雅的使用svg

背景

日前,需要开发一个配置数据表单类的框架,需要考虑框架的扩展性,以及使用的便捷性,其中图标类的引入也在考虑之中。

期望实现的效果是在新增一个svg时,仅将svg文件存放到某一个文件夹下,之后使用时通过类似于<mis-icon icon="name">这种方式即可使用。

思路

  1. 全局注册组件
  2. 使用js读取文件夹下的所有svg导入至项目中

最终使用效果

<template>
  <div>
    <!-- icon的值为svg文件名 -->
    <mis-icon icon="test" className="test-icon"></mis-icon>
  </div>
</template>

<script>
export default {
  name: 'SvgTest'
}
</script>

<style scoped>
  .test-icon{
    color: blue;
    width: 200px;
    height: 200px;
  }
  .test-icon:hover{
    color: lightblue;
  }
</style>

以下提供 vue3+vite+js 以及 vue2+webpack5+js 的实现方式

实现 - vue3+vite+js

全局注册组件

src/compoments下创建MisIcon.vue

<template>
  <svg :class="svgClass" aria-hidden="true" @click="emits('click')">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script setup>
import { computed } from "@vue/runtime-core";
const props = defineProps({
  icon: {
    type: String,
    required: true,
  },
  className: {
    type: String,
    default: "",
  },
});
const iconName = computed(() => `#icon-${props.icon}`);
const svgClass = computed(() => {
  if (props.className) {
    return "svg-icon " + props.className;
  } else {
    return "svg-icon";
  }
});
const emits = defineEmits(["click"]);
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

集中存放svg文件

src/assets/svg文件夹下存放所有svg文件

注意:如果需要修改svg的颜色,svg文件中的填充色 fill 必须删除

全局注册组件&全局导入svg

由于Vue3以应用实例方式运行,组件注册需要在main.js中的app挂钩

注:很多东西都需要与main.js中的app挂钩,我以另外的方式重写了,在这里以官方方式进行代码编写

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import MisIcon from "./compoments/MisIcon.vue";
// 配置全局svg导入用的
import 'virtual:svg-icons-register';

const app = createApp(App);
app.component('MisIcon', MisIcon);
app.mount("#app");

全局导入svg

使用 vite-plugin-svg-icons 插件

npm install vite-plugin-svg-icons -S

根目录下的ve.config.js文件中

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";

function resolve(dir) {
  return path.join(__dirname, "./", dir);
}
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [resolve("src/assets/svg")],
      // 指定symbolId格式
      symbolId: "icon-[name]",
    }),
  ]
});

src目录下的main.js

// main.js
// 配置全局svg导入用的插件
import 'virtual:svg-icons-register';

实现 - vue2+webpack+js

全局注册组件

src/compoments下创建MisIcon.vue

<template>
  <svg :class="svgClass" aria-hidden="true">
    <use :xlink:href="iconName"/>
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    icon: {
      type: String,
      required: true,
    },
    className: {
      type: String,
      default: '',
    },
  },
  computed: {
    iconName () {
      return `#icon-${this.icon}`
    },
    svgClass () {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    },
  },
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

集中存放svg文件

  1. src/assets/svg文件夹下存放所有svg文件

    注意:如果需要修改svg的颜色,svg文件中的填充色 fill 必须删除

  2. src/assets 下创建svg.js文件

    // 读取所有svg文件
    const requireAll = requireContext => requireContext.keys().map(requireContext)
    const req = require.context('/src/assets/svg', false, /\.svg$/)
    requireAll(req)
    

全局注册组件并导入svg

// main.js
import '@/assets/svg.js'
import MisIcon from '@/components/MisIcon/icon.vue' // svg组件

// 注册全局插件
Vue.component('mis-icon', MisIcon)

重要的一步 - 配置loader

根目录下的vue.config.js文件中

const path = require('path')

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

module.exports = {
  chainWebpack: config => {
    // svg 规则
    const svgRule = config.module.rule('svg') // 找到原有的svg-loader
    svgRule.uses.clear() // 清除已有的loader, 如果不清除会在原有loader之后再使用当前loader规则
    svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
    svgRule // 添加svg新的loader处理
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]',
      })

    // 修改images loader,添加svg处理
    const imagesRule = config.module.rule('images')
    imagesRule.exclude.add(resolve('src/assets/svg'))
    config.module
      .rule('images')
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
  }
}
posted @ 2021-02-20 11:17  枫子_dan  阅读(7341)  评论(0编辑  收藏  举报