三、vue3后台项目系列——更新vite配置、封装通用SVG组件、测试mock

发布于:2025-09-15 ⋅ 阅读:(14) ⋅ 点赞:(0)

前言:为了方便使用,一般会有很多图标,我们将它封装成组件,方便复用。并且基于前面我们进行更新一些vite配置,并测试跑通mock,方便后面使用。

一、更新vite配置(vite.congid.js)

主要是加入设置@通配符,加入mock的声明,完整如下:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteMockServe } from 'vite-plugin-mock'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'


export default defineConfig({
  // 配置路径别名
  resolve: {
    alias: {
      "@":path.resolve(__dirname,'src')
    }
  },
  plugins: [
    vue(),
    // 配置mock服务
    viteMockServe({
      // 本地开发时启用mock
      localEnabled: true,
      // mock文件所在目录
      mockPath: './mock/'
    }),
    createSvgIconsPlugin({
      // 指定SVG图标存放目录(使用@别名的话可以写成 '@/icons/svg',但这里需要绝对路径)
      iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')],
      // 指定symbolId格式(与SvgIcon组件中的iconName对应)
      symbolId: 'icon-[dir]-[name]',
      // 配置SVGO优化
      svgoOptions: {
        multipass: true,
        plugins: [
          {
            name: 'removeAttrs',
            params: {
              attrs: ['fill', 'fill-rule']
            }
          }
        ]
      }
    })
  ]
})

二、封装SVGICON渲染组件

# 安装处理SVG的核心插件和优化工具
npm install vite-plugin-svg-icons svgo --save-dev
<template>
  <!-- 外部 SVG 图标(通过 URL 引入) -->
  <div v-if="isexternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
  <!-- 内部 SVG 图标(使用雪碧图) -->
  <!-- aria-hidden="true":告诉屏幕阅读器该 SVG 图标是装饰性的,无需朗读,提升可访问性。 -->
  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script setup>
import { computed } from 'vue'
import { isExternal } from '@/utils/validate'

// 定义组件接收的 props
const props = defineProps({
  // 图标标识(内部图标为文件名,外部图标为URL)
  iconClass: {
    type: String,
    required: true
  },
  // 额外的CSS类名(用于自定义图标样式)
  className: {
    type: String,
    default: ''
  }
})

// 判断是否为外部图标
const isexternal = computed(() => {
  return isExternal(props.iconClass)
})

// 内部图标在雪碧图中的ID(格式:#icon-文件名)
const iconName = computed(() => {
  return `#icon-${props.iconClass}`
})

// 拼接SVG的class类名(基础类+自定义类)
const svgClass = computed(() => {
  return props.className ? `svg-icon ${props.className}` : 'svg-icon'
})

// 外部图标的样式(通过CSS mask显示)
const styleExternalIcon = computed(() => {
  return {
    mask: `url(${props.iconClass}) no-repeat 50% 50%`,
    '-webkit-mask': `url(${props.iconClass}) no-repeat 50% 50%`
  }
})

</script>

<style scoped>
/* 内部SVG图标的基础样式 */
.svg-icon {
  width: 1em;  /* 宽度为1个字体大小单位,方便通过font-size控制图标大小 */
  height: 1em; /* 高度与宽度一致,保证图标不变形 */
  vertical-align: -0.15em; /* 微调垂直对齐,解决图标与文字 baseline 不一致问题 */
  fill: currentColor; /* 填充色继承父元素的color属性,方便通过color控制图标颜色 */
  overflow: hidden;
}

/* 外部SVG图标的样式 */
.svg-external-icon {
  background-color: currentColor; /* 背景色继承父元素的color,作为图标的颜色 */
  mask-size: cover!important; /* 保证遮罩图片(外部SVG)完全覆盖元素 */
  display: inline-block; /* 使元素按行内块级显示,避免占满整行 */
}
</style>

在src下开一个utils文件夹用来存放校验代码,src/utils/validate.js(里面包含了isExternal 校验方法)

/**
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path) {
  return /^(https?:|mailto:|tel:)/.test(path)
}

测试使用该组件:

<script setup>
import SvgIcon from '@/components/SvgIcon/index.vue'

</script>

<template>
  <SvgIcon icon-class="edit" />
</template>

<style scoped>

</style>

注意:存放的svg是在这里,前面vite.config.js里面的路径也是对应的,不然无法识别,使用时,文件名称一定要对应好。

createSvgIconsPlugin({
      // 指定SVG图标存放目录(使用@别名的话可以写成 '@/icons/svg',但这里需要绝对路径)
      iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')],
      // 指定symbolId格式(与SvgIcon组件中的iconName对应)
      symbolId: 'icon-[dir]-[name]',
      // 配置SVGO优化
      svgoOptions: {
        multipass: true,
        plugins: [
          {
            name: 'removeAttrs',
            params: {
              attrs: ['fill', 'fill-rule']
            }
          }
        ]
      }
    })

三、测试mcok

记得要开一个mock文件,单独存放mock的配置。我是直接在src下创建的,即src/mock。

在mock下创建一个user.js尝试跑通功能,确保能够正常使用,后续会对这些模拟请求的操作进行模块化。

export default [
  {
    // 请求路径
    url: '/api/login',
    // 请求方法
    method: 'post',
    // 响应数据
    response: ({ body }) => {
      // 模拟验证用户名密码
      if (body.username === 'admin' && body.password === '123456') {
        return {
          code: 200,
          message: '登录成功',
          data: {
            token: 'mock-token-123456',
            userInfo: {
              id: 1,
              name: '管理员'
            }
          }
        }
      } else {
        return {
          code: 401,
          message: '用户名或密码错误'
        }
      }
    }
  }
]

在任意页面进行挂载时,尝试请求,看控制台有没有输出内容,如果有获取到数据则能够正常使用。

<script setup>
import axios from 'axios'
import { onMounted } from 'vue'

// 调用登录接口
async function login() {
  const res = await axios.post('/api/login', {
    username: 'admin',
    password: '123456'
  })
  console.log(res.data)
}

onMounted(() => {
  login()
})
</script>