vue2&3自定义svg图标组件

Posted ps酷教程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue2&3自定义svg图标组件相关的知识,希望对你有一定的参考价值。

可参考:
未来必热:SVG Sprites技术介绍
懒人神器:svg-sprite-loader实现自己的Icon组件
在Vue3项目中使用svg-sprite-loader

前置知识

在页面中,虽然可以通过如下的方式使用img标签,来引入svg图标。但是,如果这个路径很长,也是比较麻烦的。

<img src="./svg/icon.svg" />

在svg里面,可以在文档中先定义Symbol,然后svg使用的时候,只须通过标识去引用指定的svg即可,Symbol的放置顺序不一定要在最前面,案例如下:

<html>

<head>
  <meta charset="utf-8">
  <title>SVG Sprite使用</title>
  <style>
    li 
      font-size: 14px;
      margin-top: 5px;
      color: #369;
    

    .webicon 
      width: 16px;
      height: 16px;
      margin-right: 5px;
      vertical-align: -2px;
      fill: #369;
    
  </style>
</head>

<body>
  <div style="display: none;"><svg>
      <symbol id="liwu" viewBox="-80 -72.013 160 144.025">
        <path
          d="M-71.949-16.039h55.974v-55.974h-55.974V-16.039z M16.102-16.039h55.975v-55.974H16.102V-16.039z M-80,32.013h64.025v-40H-80V32.013z M80,32.013v-40H16.102v40H80z M-7.923,32.013H8.051V-72.013H-7.923V32.013z M16.102,39.936 h-32.077v24.025h32.077V39.936z M64.025,39.936h-40l15.719,32.077h24.281V39.936z M-23.898,39.936h-40v32.077H-40L-23.898,39.936z"
          transform="matrix(1 0 0 -1 0 0)"></path>
      </symbol>
      <symbol id="qianbi" viewBox="-79.5 -79.5 159 159">
        <path
          d="M79.5,32.802l-93.538-93.538l-46.699,46.699L32.802,79.5L79.5,32.802z M-79.5-32.802L-32.802-79.5H-79.5 V-32.802z"
          transform="matrix(1 0 0 -1 0 0)"></path>
      </symbol>
      <symbol id="shangchuan" viewBox="-73.623 -78.055 147.245 156.11">
        <path
          d="M0.069,32.482L64.48-32.205H36.915v-45.85h-73.83l-0.139,45.85h-27.15L0.069,32.482z M73.623,78.055V59.632 H-73.623v18.423H73.623z"
          transform="matrix(1 0 0 -1 0 0)"></path>
      </symbol>
    </svg></div>
  <h3>SVG Sprite使用示意</h3>
  <ul>
    <li><svg class="webicon">
        <use xlink:href="#qianbi"></use>
      </svg>编辑信息</li>
    <li><svg class="webicon">
        <use xlink:href="#liwu"></use>
      </svg>兑换礼物</li>
    <li><svg class="webicon">
        <use xlink:href="#shangchuan"></use>
      </svg>上传文件</li>
  </ul>
  </div>
</body>

</html>

vue3+vite自定义svg图标组件

可参考:Vue3后台管理系统(四)SVG图标

1、安装 vite-plugin-svg-icons

npm i fast-glob@3.2.11 -D
npm i vite-plugin-svg-icons@2.0.1 -D

2、创建图标文件夹

在src/assets文件夹下新建icons文件夹,用于存放下载的 SVG 图标

3、vite.config.js 插件配置

import  defineConfig  from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

import  createSvgIconsPlugin  from 'vite-plugin-svg-icons';

// https://vitejs.dev/config/
export default defineConfig(
  plugins: [
    vue(),
    createSvgIconsPlugin(
      // 指定需要缓存的图标文件夹
      iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
      // 指定symbolId格式
      symbolId: 'icon-[dir]-[name]',
    )
  ],
  resolve: 
    alias: 
      '@': path.resolve(__dirname, './src')
    
  
)

4、SvgIcon组件封装

<!--src/components/SvgIcon/index.vue-->
<template>
  <svg
      aria-hidden="true"
      class="svg-icon"
      :style="'width:' + size + ';height:' + size"
  >
    <use :xlink:href="symbolId" :fill="color"/>
  </svg>
</template>
 
<script setup lang="ts">
import computed from 'vue';
 
const props = defineProps(
  prefix: 
    type: String,
    default: 'icon'
  ,
  iconClass: 
    type: String,
    required: false
  ,
  color: 
    type: String
  ,
  size: 
    type: String,
    default: '1em'
  
);
 
const symbolId = computed(() => `#$props.prefix-$props.iconClass`);
</script>
 
<style scoped>
.svg-icon 
  overflow: hidden;
  fill: currentColor;

</style>

5、main.js 引入注册脚本

import  createApp  from 'vue'
import './style.css'
import App from './App.vue'

import router from '@/router'
import store from '@/store'

// 不知道这个东西是哪来的,但是没它的话,html下面就没有那个Symbol的定义了
import 'virtual:svg-icons-register';

import SvgIcon from '@/components/SvgIcon/index.vue'


const app = createApp(App)
app.use(router)
app.use(store)

// 注册全局组件
app.component('SvgIcon',SvgIcon)

app.mount('#app')

6、Home.vue中使用SvgIcon组件

<template>
    home
    <svg-icon icon-class="tree" size="40px"/>
    <svg-icon icon-class="tree2" size="50px"/>
</template>

<script setup>

</script>

<style lang="scss">

</style>

7、图标选择器

IconSelect.vue

在src/components文件夹下新建IconSelect文件夹,并在IconSelect文件夹下新建index.vue

<template>
    <div class="icon-select">
      <el-input
        v-model="iconName"
        clearable
        placeholder="请输入图标名称"
        @clear="filterIcons"
        @input="filterIcons"
      >
        <template #suffix><i class="el-icon-search el-input__icon" /></template>
      </el-input>
      <div class="icon-select__list">
        <div
          v-for="(item, index) in iconList"
          :key="index"
          @click="selectedIcon(item)"
        >
          <svg-icon
            color="#999"
            :icon-class="item"
            style="height: 30px; width: 16px; margin-right: 5px"
          />
          <span> item </span>
        </div>
      </div>
    </div>
  </template>
   
  <script setup>
  import  ref  from 'vue';
  import SvgIcon from '@/components/SvgIcon/index.vue';
   
  const icons = [] ;
  const modules = import.meta.glob('../../assets/icons/*.svg');
  for (const path in modules) 
    const p = path.split('assets/icons/')[1].split('.svg')[0];
    icons.push(p);
  
  const iconList = ref(icons);
   
  const iconName = ref('');
   
  const emit = defineEmits(['selected']);
   
  function filterIcons() 
    iconList.value = icons;
    if (iconName.value) 
      iconList.value = icons.filter(item => item.indexOf(iconName.value) !== -1);
    
  
   
  function selectedIcon(name) 
    emit('selected', name);
    document.body.click();
  
   
  function reset() 
    iconName.value = '';
    iconList.value = icons;
  
   
  defineExpose(
    reset
  );
  </script>
   
  <style lang="scss" scoped>
  .icon-select 
    width: 100%;
    padding: 10px;
   
    &__list 
      height: 200px;
      overflow-y: scroll;
   
      div 
        height: 30px;
        line-height: 30px;
        margin-bottom: -5px;
        cursor: pointer;
        width: 33%;
        float: left;
      
   
      span 
        display: inline-block;
        vertical-align: -0.15em;
        fill: currentColor;
        overflow: hidden;
      
    
  
  </style>

Home.vue中使用IconSelect

<template>
    home
    <!-- <svg-icon icon-class="tree" size="40px"/>
    <svg-icon icon-class="tree2" size="50px"/> -->

    <div style="width:300px">
        <icon-select @selected="selected"></icon-select>
    </div>
</template>

<script setup>
import IconSelect from '@/components/IconSelect/index.vue'
import  reactive, ref  from "vue";

const state = reactive(
    icon: '',
)

function selected(name) 
    console.log(state.icon)
    state.icon = name;


</script>

<style lang="scss"></style>

vue2自定义svg图标组件

1. 安装svg-sprite-loader

npm install svg-sprite-loader -D

2. 创建图标所在文件夹

在项目 src 目录下新建 src/icons/svg 目录(存放 svg 图标文件)。

3. 配置vue.config.js

const  defineConfig  = require('@vue/cli-service')

const path = require('path')
const resolve = dir => path.join(__dirname, dir)

module.exports = defineConfig(
  transpileDependencies: true,
  chainWebpack(config) 
    // 配置 svg-sprite-loader
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end()
    config.module
      .rule('icons')
      .test(/\\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options(
        symbolId: 'icon-[name]'
      )
      .end()
  
)

4. SvgIcon.vue图标组件封装

在src/components下创建SvgIcon.vue
(或者:在src/components下创建SvgIcon文件夹,在里边创建index.vue)

<template>
  <svg className="svg-icon" aria-hidden="true">
    <use :xlink:href="iconName"/>
  </svg>
</template>
<style>
.svg-icon 
  width: 1.5em;
  height: 1.5em;

</style>
<script>
export default 
  props: 
    iconClass: 
      type: String,
      required: true
    
  ,
  computed: 
    iconName () 
      return `#icon-$this.iconClass`
    
  

</script>

5.创建svg文件的入口文件icon.js

在 src/icons 下创建 icons 目录的入口文件 index.js ,负责svg文件的加载

import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'

在Vue中使用svg图标即封装自定义svg-icon标签

参考 Vue项目中使用svg图标   这篇软文质量不错, 依葫芦画瓢,也跑通了

1.慢慢在理解其中包含的知识

2. 把自己理解换一种方式表达一下

 我们想在vue页面使用svg图标,例如

技术图片

<template>
  <div>
    <h1>Svg实践,在页面中使用</h1>
    <svg-icon icon-class="add"></svg-icon>
    <svg-icon icon-class="auto"></svg-icon>
  </div>
</template>

<script>
export default {
  props: {},
  components: {},
  data() {
    return {};
  },
  computed: {},
  created() {},
  mounted() {},
  watch: {},
  methods: {}
};
</script>

参考上面的文章

以上代码是svg的原生用法(正确性未验证)

 

1. src/icons 目录, 导入 svg 资源文件

2. npm install svg-sprite-loader --save-dev =>package.json

3. 配置webpack.base.conf.js(build文件夹中)
//设置Webpack 用 svg-sprite-loader 加载, src/icons 目录的内容,
换一种方式:
1). 在 rules 下增加

{
    test: /.svg$/,
    loader: "svg-sprite-loader",
    include: [resolve("src/icons")],
    options: {
        symbolId: "icon-[name]"
    }
},    

//实际效果是,上面配置后webpack会加载src/icons下的index.js

2). webpack.base.conf.js 原生的 loader: ‘url-loader‘,中去掉svg,就不再额外添加
指令: exclude:[resolve(src/icons)] ,

如下:

{
    test: /.(png|jpe?g|gif)(?.*)?$/,
    loader: url-loader,
    options: {
        limit: 10000,
        name: utils.assetsPath(img/[name].[hash:7].[ext])
    }
},

4. 自定义svg组件封装svg功能

基础核心知识
srciconsindex.js 中
import SvgIcon from ‘@/components/SvgIcon‘ 的加载行为
加载 srccomponentsSvgIconindex.vue

<svg :class="svgClass" aria-hidden="true" v-on="$listeners">

在Vue中使用svg图标即封装自定义svg-icon标签
如在 SvgDemo.vue 使用如下标签

<template>
    <div>
        <h1>Svg实践,在页面中使用</h1>
        <svg-icon icon-class="add"></svg-icon>
        <svg-icon icon-class="auto"></svg-icon>
    </div>
</template>                

 

以上是关于vue2&3自定义svg图标组件的主要内容,如果未能解决你的问题,请参考以下文章

如何在Vuetify中添加自定义SVG图标 - Vue

前端常用的网址

uni-app为组件uni-icons增加自定义图标(超简单)

Bootstrap 4.0自定义汉堡图标[重复]

将自定义图标添加到字体真棒

前端技术之SVG图片(图标)创建