Template
1
0
mirror of https://github.com/un-pany/v3-admin-vite.git synced 2025-04-22 03:49:19 +08:00

perf: 优化代码

This commit is contained in:
pany 2024-12-02 16:42:32 +08:00
parent 6319defeca
commit a12d7a1724
19 changed files with 93 additions and 85 deletions

2
.gitignore vendored
View File

@ -3,8 +3,6 @@ dist
node_modules
.eslintcache
vite.config.*.timestamp*
svg-component-global.d.ts
svg-component.d.ts
# MacOS
.DS_Store

View File

@ -0,0 +1,11 @@
## 目录说明
- `common/assets/icons/preserve-color` 目录下存放带颜色的 svg icon
- `common/assets/icons` 目录存放的 svg icon 会被插件重写 `fill``stroke` 属性,使得图片自带的颜色丢失,从而继承父元素的颜色
## 使用说明
`common/assets/icons/preserve-color` 目录下需要添加 `preserve-color/` 前缀,像这样: `<SvgIcon name="preserve-color/name" />`
`common/assets/icons` 目录下则不需要,像这样: `<SvgIcon name="name" />`

View File

@ -80,11 +80,11 @@ function handleContentFullClick() {
<div>
<!-- 全屏 -->
<el-tooltip v-if="!props.content" effect="dark" :content="fullscreenTips" placement="bottom">
<SvgIcon :name="fullscreenSvgName" @click="handleFullscreenClick" />
<SvgIcon :name="fullscreenSvgName" @click="handleFullscreenClick" class="svg-icon" />
</el-tooltip>
<!-- 内容区 -->
<el-dropdown v-else :disabled="isFullscreen">
<SvgIcon :name="contentLargeSvgName" />
<SvgIcon :name="contentLargeSvgName" class="svg-icon" />
<template #dropdown>
<el-dropdown-menu>
<!-- 内容区放大 -->

View File

@ -14,16 +14,16 @@ const { isMobile } = useDevice()
<div class="search-footer">
<template v-if="!isMobile">
<span class="search-footer-item">
<SvgIcon name="keyboard-enter" />
<SvgIcon name="keyboard-enter" class="svg-icon" />
<span>确认</span>
</span>
<span class="search-footer-item">
<SvgIcon name="keyboard-up" />
<SvgIcon name="keyboard-down" />
<SvgIcon name="keyboard-up" class="svg-icon" />
<SvgIcon name="keyboard-down" class="svg-icon" />
<span>切换</span>
</span>
<span class="search-footer-item">
<SvgIcon name="keyboard-esc" />
<SvgIcon name="keyboard-esc" class="svg-icon" />
<span>关闭</span>
</span>
</template>

View File

@ -155,7 +155,7 @@ function handleReleaseUpOrDown() {
>
<el-input ref="inputRef" v-model="keyword" placeholder="搜索菜单" size="large" clearable @input="handleSearch">
<template #prefix>
<SvgIcon name="search" />
<SvgIcon name="search" class="svg-icon" />
</template>
</el-input>
<el-empty v-if="result.length === 0" description="暂无搜索结果" :image-size="100" />

View File

@ -76,12 +76,12 @@ defineExpose({ getScrollTop })
:style="itemStyle(item)"
@mouseenter="handleMouseenter(item)"
>
<SvgIcon v-if="item.meta?.svgIcon" :name="item.meta.svgIcon" />
<SvgIcon v-if="item.meta?.svgIcon" :name="item.meta.svgIcon" class="svg-icon" />
<component v-else-if="item.meta?.elIcon" :is="item.meta.elIcon" class="el-icon" />
<span class="result-item-title">
{{ item.meta?.title }}
</span>
<SvgIcon v-if="modelValue && modelValue === item.name" name="keyboard-enter" />
<SvgIcon v-if="modelValue && modelValue === item.name" name="keyboard-enter" class="svg-icon" />
</div>
</div>
</template>

View File

@ -13,7 +13,7 @@ function handleOpen() {
<template>
<div>
<el-tooltip effect="dark" content="搜索菜单" placement="bottom">
<SvgIcon name="search" @click="handleOpen" />
<SvgIcon name="search" @click="handleOpen" class="svg-icon" />
</el-tooltip>
<Modal v-model="visible" />
</div>

View File

@ -1,29 +0,0 @@
<script lang="ts" setup>
import SvgSpritesIcon, { type SvgName } from "~virtual/svg-component"
import { computed } from "vue"
type RemoveIconPrefix<T extends SvgName> = T extends `icon-${infer R}` ? R : T;
export type TSvgIconName = RemoveIconPrefix<SvgName>
interface Props {
name: TSvgIconName
}
const props = defineProps<Props>()
const iconName = computed(() => `icon-${props.name}` as SvgName)
</script>
<template>
<SvgSpritesIcon :name="iconName" class="svg-icon" />
</template>
<style lang="scss" scoped>
.svg-icon {
width: 1em;
height: 1em;
fill: currentColor;
overflow: hidden;
}
</style>

View File

@ -52,7 +52,7 @@ function resolvePath(routePath: string) {
<template v-if="!alwaysShowRootMenu && theOnlyOneChild && !theOnlyOneChild.children">
<Link v-if="theOnlyOneChild.meta" :to="resolvePath(theOnlyOneChild.path)">
<el-menu-item :index="resolvePath(theOnlyOneChild.path)">
<SvgIcon v-if="theOnlyOneChild.meta.svgIcon" :name="theOnlyOneChild.meta.svgIcon" />
<SvgIcon v-if="theOnlyOneChild.meta.svgIcon" :name="theOnlyOneChild.meta.svgIcon" class="svg-icon" />
<component v-else-if="theOnlyOneChild.meta.elIcon" :is="theOnlyOneChild.meta.elIcon" class="el-icon" />
<template v-if="theOnlyOneChild.meta.title" #title>
<span class="title">{{ theOnlyOneChild.meta.title }}</span>
@ -62,7 +62,7 @@ function resolvePath(routePath: string) {
</template>
<el-sub-menu v-else :index="resolvePath(props.item.path)" teleported>
<template #title>
<SvgIcon v-if="props.item.meta?.svgIcon" :name="props.item.meta.svgIcon" />
<SvgIcon v-if="props.item.meta?.svgIcon" :name="props.item.meta.svgIcon" class="svg-icon" />
<component v-else-if="props.item.meta?.elIcon" :is="props.item.meta.elIcon" class="el-icon" />
<span v-if="props.item.meta?.title" class="title">{{ props.item.meta.title }}</span>
</template>

View File

@ -1,8 +1,6 @@
import type { App } from "vue"
import * as ElementPlusIconsVue from "@element-plus/icons-vue"
export type TElementPlusIconName = keyof typeof ElementPlusIconsVue
export function installElementPlusIcons(app: App) {
// 注册所有 Element Plus Icon
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {

View File

@ -1,12 +1,12 @@
import type { App } from "vue"
import { installElementPlusIcons } from "./element-plus-icons"
import { installPermissionDirective } from "./permission-directive"
import { installSvgIcons } from "./svg-icons"
import { installSvgIcon } from "./svg-icon"
import { installVxeTable } from "./vxe-table"
export function installPlugins(app: App) {
installElementPlusIcons(app)
installPermissionDirective(app)
installSvgIcons(app)
installSvgIcon(app)
installVxeTable(app)
}

6
src/plugins/svg-icon.ts Normal file
View File

@ -0,0 +1,6 @@
import type { App } from "vue"
import SvgIcon from "~virtual/svg-component"
export function installSvgIcon(app: App) {
app.component("SvgIcon", SvgIcon)
}

View File

@ -1,6 +0,0 @@
import type { App } from "vue"
import SvgIcon from "@@/components/SvgIcon/index.vue" // Svg Component
export function installSvgIcons(app: App) {
app.component("SvgIcon", SvgIcon)
}

26
types/auto/svg-component-global.d.ts vendored Normal file
View File

@ -0,0 +1,26 @@
/* eslint-disable */
/* prettier-ignore */
// biome-ignore format: off
// biome-ignore lint: off
// @ts-nocheck
// Generated by unplugin-svg-component
import 'vue'
declare module 'vue' {
export interface GlobalComponents {
SvgIcon: import("vue").DefineComponent<{
name: {
type: import("vue").PropType<"dashboard" | "fullscreen-exit" | "fullscreen" | "keyboard-down" | "keyboard-enter" | "keyboard-esc" | "keyboard-up" | "search">;
default: string;
required: true;
};
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
name: {
type: import("vue").PropType<"dashboard" | "fullscreen-exit" | "fullscreen" | "keyboard-down" | "keyboard-enter" | "keyboard-esc" | "keyboard-up" | "search">;
default: string;
required: true;
};
}>>, {
name: "dashboard" | "fullscreen-exit" | "fullscreen" | "keyboard-down" | "keyboard-enter" | "keyboard-esc" | "keyboard-up" | "search";
}>;
}
}

26
types/auto/svg-component.d.ts vendored Normal file
View File

@ -0,0 +1,26 @@
/* eslint-disable */
/* prettier-ignore */
// biome-ignore format: off
// biome-ignore lint: off
// @ts-nocheck
// Generated by unplugin-svg-component
declare module '~virtual/svg-component' {
const SvgIcon: import("vue").DefineComponent<{
name: {
type: import("vue").PropType<"dashboard" | "fullscreen-exit" | "fullscreen" | "keyboard-down" | "keyboard-enter" | "keyboard-esc" | "keyboard-up" | "search">;
default: string;
required: true;
};
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
name: {
type: import("vue").PropType<"dashboard" | "fullscreen-exit" | "fullscreen" | "keyboard-down" | "keyboard-enter" | "keyboard-esc" | "keyboard-up" | "search">;
default: string;
required: true;
};
}>>, {
name: "dashboard" | "fullscreen-exit" | "fullscreen" | "keyboard-down" | "keyboard-enter" | "keyboard-esc" | "keyboard-up" | "search";
}>;
export const svgNames: ["dashboard", "fullscreen-exit", "fullscreen", "keyboard-down", "keyboard-enter", "keyboard-esc", "keyboard-up", "search"];
export type SvgName = "dashboard" | "fullscreen-exit" | "fullscreen" | "keyboard-down" | "keyboard-enter" | "keyboard-esc" | "keyboard-up" | "search";
export default SvgIcon;
}

View File

@ -1,10 +0,0 @@
import type SvgIcon from "@@/components/SvgIcon/index.vue"
export {}
// 由 app.component 全局注册的组件需要在这里声明 TS 类型才能获得 Volar 插件提供的类型提示)
declare module "vue" {
export interface GlobalComponents {
SvgIcon: typeof SvgIcon
}
}

10
types/vue-router.d.ts vendored
View File

@ -1,9 +1,11 @@
import type { TElementPlusIconName } from "@/plugins/element-plus-icons"
import type { TSvgIconName } from "@@/components/SvgIcon/index.vue"
import type * as ElementPlusIconsVue from "@element-plus/icons-vue"
import type { SvgName } from "~virtual/svg-component"
import "vue-router"
export {}
type ElementPlusIconsName = keyof typeof ElementPlusIconsVue
declare module "vue-router" {
interface RouteMeta {
/**
@ -13,11 +15,11 @@ declare module "vue-router" {
/**
* @description svg src/common/assets/icons
*/
svgIcon?: TSvgIconName
svgIcon?: SvgName
/**
* @description 使 Element Plus Icon svgIcon svgIcon
*/
elIcon?: TElementPlusIconName
elIcon?: ElementPlusIconsName
/**
* @description false true
*/

View File

@ -94,26 +94,12 @@ export default defineConfig(({ mode }) => {
vueJsx(),
// 将 SVG 文件转化为 Vue 组件
svgLoader({ defaultImport: "url" }),
// 生成 SVG 雪碧图
// github repo: https://github.com/Jevon617/unplugin-svg-component
// 自动生成 SvgIcon 组件和 SVG 雪碧图
UnpluginSvgComponent({
/** 图标所在的目录 */
iconDir: [
resolve(root, "src/common/assets/icons"),
resolve(root, "src/common/assets/icons/preserve-color")
],
/** 是否生成 d.ts 文件,开启 dev server 或更改 iconDir 目录中文件时自动生成对应文件 */
iconDir: [resolve(__dirname, "src/common/assets/icons")],
preserveColor: resolve(__dirname, "src/common/assets/icons/preserve-color"),
dts: true,
/** 保留原有颜色 SVG 目录(适用于存放多色图标) */
preserveColor: resolve(root, "src/common/assets/icons/preserve-color"),
/** 输出 d.ts 文件的目录 */
dtsDir: resolve(root, "types"),
/** 给每个 svg name 加上前缀 */
prefix: "icon",
/** 自定义生成的组件名,默认值为 "SvgIcon" */
componentName: "SvgSpritesIcon",
/** 控制注入 SVG 元素的方法 */
domInsertionStrategy: "dynamic",
dtsDir: resolve(__dirname, "types/auto"),
treeShaking: false
}),
// 原子化 CSS