mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-11-12 03:33:41 +08:00
1
src/assets/svg/custom-icon.svg
Normal file
1
src/assets/svg/custom-icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--mdi" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path fill="currentColor" d="M19 10c0 1.38-2.12 2.5-3.5 2.5s-2.75-1.12-2.75-2.5h-1.5c0 1.38-1.37 2.5-2.75 2.5S5 11.38 5 10h-.75c-.16.64-.25 1.31-.25 2a8 8 0 0 0 8 8a8 8 0 0 0 8-8c0-.69-.09-1.36-.25-2H19m-7-6C9.04 4 6.45 5.61 5.07 8h13.86C17.55 5.61 14.96 4 12 4m10 8a10 10 0 0 1-10 10A10 10 0 0 1 2 12A10 10 0 0 1 12 2a10 10 0 0 1 10 10m-10 5.23c-1.75 0-3.29-.73-4.19-1.81L9.23 14c.45.72 1.52 1.23 2.77 1.23s2.32-.51 2.77-1.23l1.42 1.42c-.9 1.08-2.44 1.81-4.19 1.81Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 702 B |
24
src/components/custom/SvgIcon.vue
Normal file
24
src/components/custom/SvgIcon.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<svg aria-hidden="true" width="1em" height="1em" class="inline-block">
|
||||
<use :xlink:href="symbolId" fill="currentColor" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
interface Props {
|
||||
/** 前缀 */
|
||||
prefix?: string;
|
||||
/** 图标名称(图片的文件名) */
|
||||
icon: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
prefix: 'icon-custom'
|
||||
});
|
||||
|
||||
const symbolId = computed(() => `#${props.prefix}-${props.icon}`);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -2,6 +2,7 @@ import 'uno.css';
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import 'swiper/css/pagination';
|
||||
import 'virtual:svg-icons-register';
|
||||
import '../styles/css/global.css';
|
||||
|
||||
/** import static assets: css, js , font and so on. - [引入静态资源,css、js和字体文件等] */
|
||||
|
||||
2
src/typings/route.d.ts
vendored
2
src/typings/route.d.ts
vendored
@@ -94,6 +94,8 @@ declare namespace AuthRoute {
|
||||
keepAlive?: boolean;
|
||||
/** 菜单和面包屑对应的图标 */
|
||||
icon?: string;
|
||||
/** 自定义的菜单和面包屑对应的图标 */
|
||||
customIcon?: string;
|
||||
/** 是否在菜单中隐藏(一些列表、表格的详情页面需要通过参数跳转,所以不能显示在菜单中) */
|
||||
hide?: boolean;
|
||||
/** 外链链接 */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { h } from 'vue';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import SvgIcon from '@/components/custom/SvgIcon.vue';
|
||||
|
||||
/**
|
||||
* 动态渲染iconify
|
||||
@@ -17,3 +18,21 @@ export function iconifyRender(icon: string, color?: string, size?: number) {
|
||||
}
|
||||
return () => h(Icon, { icon, style });
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态渲染自定义图标
|
||||
* @param icon - 图标名称
|
||||
* @param color - 图标颜色
|
||||
* @param size - 图标大小
|
||||
*/
|
||||
export function customIconRender(icon: string, color?: string, size?: number) {
|
||||
const style: { color?: string; size?: string } = {};
|
||||
if (color) {
|
||||
style.color = color;
|
||||
}
|
||||
if (size) {
|
||||
style.size = `${size}px`;
|
||||
}
|
||||
|
||||
return () => h(SvgIcon, { icon, style });
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { iconifyRender } from '../common';
|
||||
import { iconifyRender, customIconRender } from '../common';
|
||||
|
||||
/** 路由不转换菜单 */
|
||||
function hideInMenu(route: AuthRoute.Route) {
|
||||
@@ -6,13 +6,21 @@ function hideInMenu(route: AuthRoute.Route) {
|
||||
}
|
||||
|
||||
/** 给菜单添加可选属性 */
|
||||
function addPartialProps(menuItem: GlobalMenuOption, icon?: string, children?: GlobalMenuOption[]) {
|
||||
const item = { ...menuItem };
|
||||
if (icon) {
|
||||
Object.assign(item, { icon: iconifyRender(icon) });
|
||||
function addPartialProps(config: {
|
||||
menu: GlobalMenuOption;
|
||||
icon?: string;
|
||||
customIcon?: string;
|
||||
children?: GlobalMenuOption[];
|
||||
}) {
|
||||
const item = { ...config.menu };
|
||||
if (config.icon) {
|
||||
Object.assign(item, { icon: iconifyRender(config.icon) });
|
||||
}
|
||||
if (children) {
|
||||
Object.assign(item, { children });
|
||||
if (config.customIcon) {
|
||||
Object.assign(item, { icon: customIconRender(config.customIcon) });
|
||||
}
|
||||
if (config.children) {
|
||||
Object.assign(item, { children: config.children });
|
||||
}
|
||||
return item;
|
||||
}
|
||||
@@ -30,16 +38,17 @@ export function transformAuthRouteToMenu(routes: AuthRoute.Route[]): GlobalMenuO
|
||||
if (route.children) {
|
||||
menuChildren = transformAuthRouteToMenu(route.children);
|
||||
}
|
||||
const menuItem: GlobalMenuOption = addPartialProps(
|
||||
{
|
||||
const menuItem: GlobalMenuOption = addPartialProps({
|
||||
menu: {
|
||||
key: routeName,
|
||||
label: meta.title,
|
||||
routeName,
|
||||
routePath: path
|
||||
},
|
||||
meta?.icon,
|
||||
menuChildren
|
||||
);
|
||||
icon: meta.icon,
|
||||
customIcon: meta.customIcon,
|
||||
children: menuChildren
|
||||
});
|
||||
|
||||
if (!hideInMenu(route)) {
|
||||
globalMenu.push(menuItem);
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
<web-site-link label="iconify地址:" link="https://icones.js.org/" class="mt-10px" />
|
||||
</template>
|
||||
</n-card>
|
||||
<n-card title="SvgIcon 示例" class="mt-10px shadow-sm rounded-16px">
|
||||
<n-card title="自定义图标示例" class="mt-10px shadow-sm rounded-16px">
|
||||
<div class="pb-12px text-16px">
|
||||
在src/assets/svg文件夹下的svg文件,通过在template里面以 icon-custom-{文件名} 直接渲染,动态渲染需要import组件
|
||||
在src/assets/svg文件夹下的svg文件,通过在template里面以 icon-custom-{文件名} 直接渲染
|
||||
</div>
|
||||
<div class="grid grid-cols-10">
|
||||
<div class="mt-5px flex-x-center">
|
||||
@@ -27,8 +27,11 @@
|
||||
<div class="mt-5px flex-x-center">
|
||||
<icon-custom-cast class="text-20px text-error" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="py-12px text-16px">通过SvgIcon组件动态渲染, 菜单通过meta的customIcon属性渲染自定义图标</div>
|
||||
<div class="grid grid-cols-10">
|
||||
<div v-for="(item, index) in customIcons" :key="index" class="mt-5px flex-x-center">
|
||||
<component :is="item" class="text-30px text-primary" />
|
||||
<svg-icon :icon="item" class="text-30px text-primary" />
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
@@ -39,16 +42,10 @@
|
||||
import { ref } from 'vue';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import { icons } from './icons';
|
||||
import CustomActivity from '~icons/custom/activity.svg';
|
||||
import CustomAtSign from '~icons/custom/at-sign.svg';
|
||||
import CustomCast from '~icons/custom/cast.svg';
|
||||
import CustomChrome from '~icons/custom/chrome.svg';
|
||||
import CustomCopy from '~icons/custom/copy.svg';
|
||||
import CustomWind from '~icons/custom/wind.svg';
|
||||
|
||||
const selectValue = ref('');
|
||||
|
||||
const customIcons = [CustomActivity, CustomAtSign, CustomCast, CustomChrome, CustomCopy, CustomWind];
|
||||
const customIcons = ['custom-icon', 'activity', 'at-sign', 'cast', 'chrome', 'copy', 'wind'];
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
Reference in New Issue
Block a user