vben
authored
|
1
|
<template>
|
|
2
3
4
5
6
7
8
|
<SvgIcon
:size="size"
:name="getSvgIcon"
v-if="isSvgIcon"
:class="[$attrs.class, 'anticon']"
:spin="spin"
/>
|
Vben
authored
|
9
10
11
|
<span
v-else
ref="elRef"
|
LiuYa
authored
|
12
|
:class="[$attrs.class, 'app-iconify anticon', spin && 'app-iconify-spin']"
|
Vben
authored
|
13
14
|
:style="getWrapStyle"
></span>
|
vben
authored
|
15
16
17
18
19
20
21
22
23
24
25
26
27
|
</template>
<script lang="ts">
import type { PropType } from 'vue';
import {
defineComponent,
ref,
watch,
onMounted,
nextTick,
unref,
computed,
CSSProperties,
} from 'vue';
|
vben
authored
|
28
|
import SvgIcon from './src/SvgIcon.vue';
|
vben
authored
|
29
30
31
|
import Iconify from '@purge-icons/generated';
import { isString } from '/@/utils/is';
import { propTypes } from '/@/utils/propTypes';
|
Vben
authored
|
32
|
|
Vben
authored
|
33
|
const SVG_END_WITH_FLAG = '|svg';
|
vben
authored
|
34
|
export default defineComponent({
|
vben
authored
|
35
|
name: 'Icon',
|
Vben
authored
|
36
|
components: { SvgIcon },
|
vben
authored
|
37
38
39
40
41
42
43
44
45
46
|
props: {
// icon name
icon: propTypes.string,
// icon color
color: propTypes.string,
// icon size
size: {
type: [String, Number] as PropType<string | number>,
default: 16,
},
|
LiuYa
authored
|
47
|
spin: propTypes.bool.def(false),
|
vben
authored
|
48
49
50
|
prefix: propTypes.string.def(''),
},
setup(props) {
|
vben
authored
|
51
|
const elRef = ref(null);
|
vben
authored
|
52
|
|
Vben
authored
|
53
54
55
|
const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG));
const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, ''));
const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`);
|
vben
authored
|
56
57
|
const update = async () => {
|
Vben
authored
|
58
59
|
if (unref(isSvgIcon)) return;
|
vben
authored
|
60
|
const el: any = unref(elRef);
|
Vben
authored
|
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
if (!el) return;
await nextTick();
const icon = unref(getIconRef);
if (!icon) return;
const svg = Iconify.renderSVG(icon, {});
if (svg) {
el.textContent = '';
el.appendChild(svg);
} else {
const span = document.createElement('span');
span.className = 'iconify';
span.dataset.icon = icon;
el.textContent = '';
el.appendChild(span);
|
vben
authored
|
77
78
79
|
}
};
|
vben
authored
|
80
81
82
83
84
|
const getWrapStyle = computed((): CSSProperties => {
const { size, color } = props;
let fs = size;
if (isString(size)) {
fs = parseInt(size, 10);
|
vben
authored
|
85
|
}
|
vben
authored
|
86
87
88
89
90
91
92
|
return {
fontSize: `${fs}px`,
color: color,
display: 'inline-flex',
};
});
|
vben
authored
|
93
|
|
vben
authored
|
94
|
watch(() => props.icon, update, { flush: 'post' });
|
vben
authored
|
95
96
97
|
onMounted(update);
|
Vben
authored
|
98
|
return { elRef, getWrapStyle, isSvgIcon, getSvgIcon };
|
vben
authored
|
99
100
101
102
103
104
|
},
});
</script>
<style lang="less">
.app-iconify {
display: inline-block;
|
Vben
authored
|
105
|
// vertical-align: middle;
|
LiuYa
authored
|
106
107
108
109
110
111
|
&-spin {
svg {
animation: loadingCircle 1s infinite linear;
}
}
|
vben
authored
|
112
113
114
115
116
117
118
|
}
span.iconify {
display: block;
min-width: 1em;
min-height: 1em;
border-radius: 100%;
|
vben
authored
|
119
|
background-color: @iconify-bg-color;
|
vben
authored
|
120
121
|
}
</style>
|