Skip to content

Commit a2269bc

Browse files
author
奇淼(piexlmax
authored
优化自定义图标功能,修复上线后无法展示自定义图标的问题。 (#1625)
* 修改自定义图标使用方式 * 优化自定义icon功能
1 parent d41394c commit a2269bc

File tree

6 files changed

+113
-19
lines changed

6 files changed

+113
-19
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<template>
2+
<svg
3+
:class="svgClass"
4+
v-bind="$attrs"
5+
:color="color"
6+
>
7+
<use
8+
:xlink:href="'#'+name"
9+
rel="external nofollow"
10+
/>
11+
</svg>
12+
</template>
13+
<script setup>
14+
import { defineProps, computed } from 'vue'
15+
const props = defineProps({
16+
name: {
17+
type: String,
18+
required: true
19+
},
20+
color: {
21+
type: String,
22+
default: 'currentColor'
23+
}
24+
})
25+
26+
const svgClass = computed(() => {
27+
if (props.name) {
28+
return `svg-icon ${props.name}`
29+
}
30+
return 'svg-icon'
31+
})
32+
</script>
33+
<style scoped>
34+
.svg-icon {
35+
@apply w-4 h-4;
36+
fill: currentColor;
37+
vertical-align: middle;
38+
}
39+
</style>

web/src/core/global.js

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,29 @@ import { h } from 'vue'
33

44
// 统一导入el-icon图标
55
import * as ElIconModules from '@element-plus/icons-vue'
6+
import svgIcon from '@/components/svgIcon/svgIcon.vue'
67
// 导入转换图标名称的函数
78

8-
const createIconComponent = (svgContent) => ({
9+
const createIconComponent = (name) => ({
910
name: 'SvgIcon',
10-
props: {
11-
iconClass: {
12-
type: String,
13-
default: '',
14-
},
15-
className: {
16-
type: String,
17-
default: '',
18-
},
19-
},
2011
render() {
21-
const { className } = this
22-
return h('span', {
23-
class: className,
24-
ariaHidden: true,
25-
innerHTML: svgContent,
12+
return h(svgIcon, {
13+
name: name,
2614
})
2715
},
2816
})
2917

3018
const registerIcons = async(app) => {
3119
const iconModules = import.meta.glob('@/assets/icons/**/*.svg')
3220
for (const path in iconModules) {
33-
const response = await fetch(path)
34-
const svgContent = await response.text()
3521
const iconName = path.split('/').pop().replace(/\.svg$/, '')
3622
// 如果iconName带空格则不加入到图标库中并且提示名称不合法
23+
console.log(iconName)
3724
if (iconName.indexOf(' ') !== -1) {
3825
console.error(`icon ${iconName}.svg includes whitespace`)
3926
continue
4027
}
41-
const iconComponent = createIconComponent(svgContent)
28+
const iconComponent = createIconComponent(iconName)
4229
config.logs.push({
4330
'key': iconName,
4431
'label': iconName,
@@ -52,6 +39,7 @@ export const register = (app) => {
5239
for (const iconName in ElIconModules) {
5340
app.component(iconName, ElIconModules[iconName])
5441
}
42+
app.component('SvgIcon', svgIcon)
5543
registerIcons(app)
5644
app.config.globalProperties.$GIN_VUE_ADMIN = config
5745
}

web/src/style/main.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,3 +688,6 @@ li {
688688
#nprogress .bar {
689689
background: #29d !important;
690690
}
691+
.gva-customer-icon{
692+
@apply w-4 h-4;
693+
}

web/src/view/login/index.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<div class="z-[999] pt-12 pb-10 md:w-96 w-full rounded-lg flex flex-col justify-between box-border">
1313
<div>
1414
<div class="flex items-center justify-center">
15+
1516
<img
1617
class="w-24"
1718
:src="$GIN_VUE_ADMIN.appLogo"

web/vite.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import vuePlugin from '@vitejs/plugin-vue'
1111
import GvaPosition from './vitePlugin/gvaPosition'
1212
import GvaPositionServer from './vitePlugin/codeServer'
1313
import fullImportPlugin from './vitePlugin/fullImport/fullImport.js'
14+
import { svgBuilder } from './vitePlugin/svgIcon/svgIcon.js'
1415
// @see https://cn.vitejs.dev/config/
1516
export default ({
1617
command,
@@ -87,6 +88,7 @@ export default ({
8788
targets: ['Android > 39', 'Chrome >= 60', 'Safari >= 10.1', 'iOS >= 10.3', 'Firefox >= 54', 'Edge >= 15'],
8889
}),
8990
vuePlugin(),
91+
svgBuilder('./src/assets/icons/'),
9092
[Banner(`\n Build based on gin-vue-admin \n Time : ${timestamp}`)]
9193
],
9294
css: {

web/vitePlugin/svgIcon/svgIcon.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { readFileSync, readdirSync } from 'fs'
2+
const svgTitle = /<svg([^>+].*?)>/
3+
const clearHeightWidth = /(width|height)="([^>+].*?)"/g
4+
const hasViewBox = /(viewBox="[^>+].*?")/g
5+
const clearReturn = /(\r)|(\n)/g
6+
function findSvgFile(dir) {
7+
const svgRes = []
8+
const dirents = readdirSync(dir, {
9+
withFileTypes: true
10+
})
11+
for (const dirent of dirents) {
12+
if (dirent.isDirectory()) {
13+
svgRes.push(...findSvgFile(dir + dirent.name + '/'))
14+
} else {
15+
const svg = readFileSync(dir + dirent.name)
16+
.toString()
17+
.replace(clearReturn, '')
18+
.replace(svgTitle, ($1, $2) => {
19+
// console.log(++i)
20+
// console.log(dirent.name)
21+
let width = 0
22+
let height = 0
23+
let content = $2.replace(clearHeightWidth, (s1, s2, s3) => {
24+
if (s2 === 'width') {
25+
width = s3
26+
} else if (s2 === 'height') {
27+
height = s3
28+
}
29+
return ''
30+
})
31+
if (!hasViewBox.test($2)) {
32+
content += `viewBox="0 0 ${width} ${height}"`
33+
}
34+
return `<symbol id="${dirent.name.replace('.svg', '')}" ${content}>`
35+
})
36+
.replace('</svg>', '</symbol>')
37+
svgRes.push(svg)
38+
}
39+
}
40+
return svgRes
41+
}
42+
export const svgBuilder = (path) => {
43+
if (path === '') return
44+
const res = findSvgFile(path)
45+
// console.log(res.length)
46+
// const res = []
47+
return {
48+
name: 'svg-transform',
49+
transformIndexHtml(html) {
50+
return html.replace(
51+
'<body>',
52+
`
53+
<body>
54+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
55+
${res.join('')}
56+
</svg>
57+
`
58+
)
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)