Vue学习笔记 之 Svg图标组件的实现步骤

1、安装依赖

首先需要安装svg-sprite-loader依赖,命令如下,这在在学习的过程中,就是因为没有下载该依赖,导致图标一直无法正常显示。

powershell 复制代码
npm install svg-sprite-loader --save-dev --force

2、配置svg图片处理规则

通过使用svg-sprite-loader组件,将svg的图标文件生产雪碧图(Sprite),在vue.config.js文件中进行配置,具体如下:

javascript 复制代码
//用于导入Node.js核心模块 path 的方法。path 模块提供了处理文件路径的实用工具,可以用于处理和操作文件路径字符串。
const path = require('path')
//定义了一个名为 resolve 的函数,用于将相对路径转换为绝对路径。__dirname 是 Node.js 中的一个全局变量,表示当前模块文件所在的目录的绝对路径。
function resolve(dir) {
  return path.join(__dirname, dir)
}

module.exports = {
  lintOnSave: false,
  transpileDependencies: ["vue"],
  publicPath: '/sys', // 设置上下文路径,与Tomcat或Nginx中的上下文路径保持一致
  indexPath: 'index.html', // 相对于打包路径index.html的路径
  outputDir: 'sys', // 'dist', 生产环境构建文件的目录
  productionSourceMap: true,
  devServer: {
    port: 8881,
    headers: {
      'Access-Control-Allow-Origin': '*',
    }
  },
  chainWebpack(config) {
	//覆盖默认配置中处理svg的规则
    config.module
      .rule('svg')//定义规则名称,必须为svg,为了覆盖该规则
      .exclude.add(resolve('src/components/SvgIcon'))
      .end()
	//定义处理指定目录下svg图片的规则
    config.module
      .rule('icons1')//定义规则名称,可以自定义
      .test(/\.svg$/)//表示该规则只适用于后缀为 .svg 的文件。
      .include.add(resolve('src/components/SvgIcon'))//只对这个目录下的SVG文件应用该规则。
      .end()
      .use('svg-sprite-loader')// 指定了使用 svg-sprite-loader 这个loader来处理满足该规则的SVG文件。
      .loader('svg-sprite-loader')//指定了要使用的loader为 svg-sprite-loader。
      .options({//对 svg-sprite-loader 的配置选项,通过 symbolId 可以设置每个图标的标识符,这里使用 icon-[name] 表示使用图标文件的名称作为标识符。
        symbolId: 'icon-[name]'
      })
      .end()
  }
};

雪碧图(Sprite)是一种将多个小图标或图片合并到一个大图中的技术。通过将多个图标放置在同一张图上,并通过CSS的background-position属性来控制显示不同的图标位置,可以减少网络请求次数,提高页面加载速度和性能。

3、定义svg-icon组件

svg-icon组件包括了svg文件(svg图片)、index.vue和index.js三部分内容。其中,svg文件,主要包括了各个图标对应的svg文件,上述vue.config.js文件中的配置,就是将该文件下的文件生成雪碧图;index.vue用来定义图标的vue组件;index.js实现了svg-icon组件的注册。具体实现如下:

index.vue页面,代码如下:

html 复制代码
<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 '@/utils/validate'

export default {
  name: 'SvgIcon',
  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: 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>

index.js文件,代码如下:

javascript 复制代码
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon/index.vue'// svg component

// 注册
Vue.component('svg-icon', SvgIcon)
//在当前文件所在目录下的 ./svg 目录中查找所有以 .svg 结尾的文件,并将匹配的文件创建一个模块上下文
const req = require.context('./svg', false, /\.svg$/)
//将模块上下文中的所有模块导入,并注册为SvgIcon组件的子组件。
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

处理后的数据:

4、svg图标使用和展示

这里实现了一个展示全部svg图标的页面,包括了svg-icons.js文件和index.vue文件,其中,svg-icons.js主要读取所有的svg图标的名称;index.vue定义了展示图标的页面。

svg-icons.js代码实现如下,类似上述index.js文件,读取文件目录,获取文件名称:

javascript 复制代码
const req = require.context('../SvgIcon/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()

const re = /\.\/(.*)\.svg/

const svgIcons = requireAll(req).map(i => {
  return i.match(re)[1]
})
console.log(svgIcons);
export default svgIcons

index.vue页面代码实现如下:

html 复制代码
<template>
  <div class="icons-container">
    <el-tabs type="border-card">
      <el-tab-pane label="Icons">
        <div v-for="item of svgIcons" :key="item">
          <el-tooltip placement="top">
            <div slot="content">
              {{ generateIconCode(item) }}
            </div>
            <div class="icon-item">
              <svg-icon :icon-class="item" class-name="disabled" />
              <span>{{ item }}</span>
            </div>
          </el-tooltip>
        </div>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
import svgIcons from './svg-icons'

export default {
  name: 'Icons',
  data() {
    return {
      svgIcons
    }
  },
  methods: {
    generateIconCode(symbol) {
      return `<svg-icon icon-class="${symbol}" />`
    }
  }
}
</script>

<style lang="scss" scoped>
.icons-container {
  margin: 10px 20px 0;
  overflow: hidden;
  .icon-item {
    margin: 20px;
    height: 85px;
    text-align: center;
    width: 100px;
    float: left;
    font-size: 30px;
    color: #24292e;
    cursor: pointer;
  }
  span {
    display: block;
    font-size: 16px;
    margin-top: 10px;
  }
  .disabled {
    pointer-events: none;
  }
}
</style>
相关推荐
B1nna3 小时前
Redis学习(三)缓存
redis·学习·缓存
LCG元3 小时前
Vue.js组件开发-使用vue-pdf显示PDF
vue.js
_im.m.z3 小时前
【设计模式学习笔记】1. 设计模式概述
笔记·学习·设计模式
哥谭居民00014 小时前
将一个组件的propName属性与父组件中的variable变量进行双向绑定的vue3(组件传值)
javascript·vue.js·typescript·npm·node.js·css3
烟波人长安吖~5 小时前
【目标跟踪+人流计数+人流热图(Web界面)】基于YOLOV11+Vue+SpringBoot+Flask+MySQL
vue.js·pytorch·spring boot·深度学习·yolo·目标跟踪
胡西风_foxww5 小时前
【ES6复习笔记】迭代器(10)
前端·笔记·迭代器·es6·iterator
PleaSure乐事5 小时前
使用Vue的props进行组件传递校验时出现 Extraneous non-props attributes的解决方案
vue.js
左漫在成长6 小时前
王佩丰24节Excel学习笔记——第十九讲:Indirect函数
笔记·学习·excel
土豆炒马铃薯。6 小时前
【Vue】前端使用node.js对数据库直接进行CRUD操作
前端·javascript·vue.js·node.js·html5
纪伊路上盛名在7 小时前
Max AI prompt1
笔记·学习·学习方法