提交 | 用户 | 时间
|
820397
|
1 |
<script lang="ts" setup> |
H |
2 |
import { CSSProperties } from 'vue' |
|
3 |
import { cloneDeep } from 'lodash-es' |
|
4 |
import { IconJson } from '@/components/Icon/src/data' |
|
5 |
|
|
6 |
defineOptions({ name: 'IconSelect' }) |
|
7 |
|
|
8 |
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined |
|
9 |
|
|
10 |
const props = defineProps({ |
|
11 |
modelValue: { |
|
12 |
require: false, |
|
13 |
type: String |
9259c2
|
14 |
}, |
H |
15 |
clearable: { |
|
16 |
require: false, |
|
17 |
type: Boolean |
820397
|
18 |
} |
H |
19 |
}) |
|
20 |
const emit = defineEmits<{ (e: 'update:modelValue', v: string) }>() |
|
21 |
|
|
22 |
const visible = ref(false) |
|
23 |
const inputValue = toRef(props, 'modelValue') |
|
24 |
const iconList = ref(IconJson) |
|
25 |
const icon = ref('add-location') |
|
26 |
const currentActiveType = ref('ep:') |
|
27 |
// 深拷贝图标数据,前端做搜索 |
|
28 |
const copyIconList = cloneDeep(iconList.value) |
|
29 |
|
|
30 |
const pageSize = ref(96) |
|
31 |
const currentPage = ref(1) |
|
32 |
|
|
33 |
// 搜索条件 |
|
34 |
const filterValue = ref('') |
|
35 |
|
|
36 |
const tabsList = [ |
|
37 |
{ |
|
38 |
label: 'Element Plus', |
|
39 |
name: 'ep:' |
|
40 |
}, |
|
41 |
{ |
|
42 |
label: 'Font Awesome 4', |
|
43 |
name: 'fa:' |
|
44 |
}, |
|
45 |
{ |
|
46 |
label: 'Font Awesome 5 Solid', |
|
47 |
name: 'fa-solid:' |
|
48 |
} |
|
49 |
] |
|
50 |
|
|
51 |
const pageList = computed(() => { |
|
52 |
if (currentPage.value === 1) { |
|
53 |
return copyIconList[currentActiveType.value] |
|
54 |
?.filter((v) => v.includes(filterValue.value)) |
|
55 |
.slice(currentPage.value - 1, pageSize.value) |
|
56 |
} else { |
|
57 |
return copyIconList[currentActiveType.value] |
|
58 |
?.filter((v) => v.includes(filterValue.value)) |
|
59 |
.slice( |
|
60 |
pageSize.value * (currentPage.value - 1), |
|
61 |
pageSize.value * (currentPage.value - 1) + pageSize.value |
|
62 |
) |
|
63 |
} |
|
64 |
}) |
|
65 |
const iconCount = computed(() => { |
|
66 |
return copyIconList[currentActiveType.value] == undefined |
|
67 |
? 0 |
|
68 |
: copyIconList[currentActiveType.value].length |
|
69 |
}) |
|
70 |
|
|
71 |
const iconItemStyle = computed((): ParameterCSSProperties => { |
|
72 |
return (item) => { |
|
73 |
if (inputValue.value === currentActiveType.value + item) { |
|
74 |
return { |
|
75 |
borderColor: 'var(--el-color-primary)', |
|
76 |
color: 'var(--el-color-primary)' |
|
77 |
} |
|
78 |
} |
|
79 |
} |
|
80 |
}) |
|
81 |
|
|
82 |
function handleClick({ props }) { |
|
83 |
currentPage.value = 1 |
|
84 |
currentActiveType.value = props.name |
|
85 |
emit('update:modelValue', currentActiveType.value + iconList.value[currentActiveType.value][0]) |
|
86 |
icon.value = iconList.value[currentActiveType.value][0] |
|
87 |
} |
|
88 |
|
|
89 |
function onChangeIcon(item) { |
|
90 |
icon.value = item |
|
91 |
emit('update:modelValue', currentActiveType.value + item) |
|
92 |
visible.value = false |
|
93 |
} |
|
94 |
|
|
95 |
function onCurrentChange(page) { |
|
96 |
currentPage.value = page |
|
97 |
} |
|
98 |
|
9259c2
|
99 |
function clearIcon() { |
H |
100 |
icon.value = '' |
|
101 |
emit('update:modelValue', '') |
|
102 |
visible.value = false |
|
103 |
} |
|
104 |
|
820397
|
105 |
watch( |
H |
106 |
() => { |
|
107 |
return props.modelValue |
|
108 |
}, |
|
109 |
() => { |
|
110 |
if (props.modelValue && props.modelValue.indexOf(':') >= 0) { |
|
111 |
currentActiveType.value = props.modelValue.substring(0, props.modelValue.indexOf(':') + 1) |
|
112 |
icon.value = props.modelValue.substring(props.modelValue.indexOf(':') + 1) |
|
113 |
} |
|
114 |
} |
|
115 |
) |
|
116 |
watch( |
|
117 |
() => { |
|
118 |
return filterValue.value |
|
119 |
}, |
|
120 |
() => { |
|
121 |
currentPage.value = 1 |
|
122 |
} |
|
123 |
) |
|
124 |
</script> |
|
125 |
|
|
126 |
<template> |
|
127 |
<div class="selector"> |
9259c2
|
128 |
<ElInput v-model="inputValue" @click="visible = !visible" :clearable="props.clearable" @clear="clearIcon"> |
820397
|
129 |
<template #append> |
H |
130 |
<ElPopover |
|
131 |
:popper-options="{ |
|
132 |
placement: 'auto' |
|
133 |
}" |
|
134 |
:visible="visible" |
9259c2
|
135 |
:width="355" |
820397
|
136 |
popper-class="pure-popper" |
H |
137 |
trigger="click" |
|
138 |
> |
|
139 |
<template #reference> |
|
140 |
<div |
|
141 |
class="h-32px w-40px flex cursor-pointer items-center justify-center" |
|
142 |
@click="visible = !visible" |
|
143 |
> |
|
144 |
<Icon :icon="currentActiveType + icon" /> |
|
145 |
</div> |
|
146 |
</template> |
|
147 |
|
|
148 |
<ElInput v-model="filterValue" class="p-2" clearable placeholder="搜索图标" /> |
|
149 |
<ElDivider border-style="dashed" /> |
|
150 |
|
|
151 |
<ElTabs v-model="currentActiveType" @tab-click="handleClick"> |
|
152 |
<ElTabPane |
|
153 |
v-for="(pane, index) in tabsList" |
|
154 |
:key="index" |
|
155 |
:label="pane.label" |
|
156 |
:name="pane.name" |
|
157 |
> |
|
158 |
<ElDivider border-style="dashed" class="tab-divider" /> |
|
159 |
<ElScrollbar height="220px"> |
9259c2
|
160 |
<ul class="ml-2 flex flex-wrap"> |
820397
|
161 |
<li |
H |
162 |
v-for="(item, key) in pageList" |
|
163 |
:key="key" |
|
164 |
:style="iconItemStyle(item)" |
|
165 |
:title="item" |
|
166 |
class="icon-item mr-2 mt-1 w-1/10 flex cursor-pointer items-center justify-center border border-solid p-2" |
|
167 |
@click="onChangeIcon(item)" |
|
168 |
> |
|
169 |
<Icon :icon="currentActiveType + item" /> |
|
170 |
</li> |
|
171 |
</ul> |
|
172 |
</ElScrollbar> |
|
173 |
</ElTabPane> |
|
174 |
</ElTabs> |
|
175 |
<ElDivider border-style="dashed" /> |
|
176 |
|
|
177 |
<ElPagination |
|
178 |
:current-page="currentPage" |
|
179 |
:page-size="pageSize" |
|
180 |
:total="iconCount" |
|
181 |
background |
|
182 |
class="h-10 flex items-center justify-center" |
|
183 |
layout="prev, pager, next" |
9259c2
|
184 |
size="small" |
820397
|
185 |
@current-change="onCurrentChange" |
H |
186 |
/> |
|
187 |
</ElPopover> |
|
188 |
</template> |
|
189 |
</ElInput> |
|
190 |
</div> |
|
191 |
</template> |
|
192 |
|
|
193 |
<style lang="scss" scoped> |
|
194 |
.el-divider--horizontal { |
|
195 |
margin: 1px auto !important; |
|
196 |
} |
|
197 |
|
|
198 |
.tab-divider.el-divider--horizontal { |
|
199 |
margin: 0 !important; |
|
200 |
} |
|
201 |
|
|
202 |
.icon-item { |
|
203 |
&:hover { |
|
204 |
color: var(--el-color-primary); |
|
205 |
border-color: var(--el-color-primary); |
|
206 |
transform: scaleX(1.05); |
|
207 |
transition: all 0.4s; |
|
208 |
} |
|
209 |
} |
|
210 |
|
|
211 |
:deep(.el-tabs__nav-next) { |
|
212 |
font-size: 15px; |
|
213 |
line-height: 32px; |
|
214 |
box-shadow: -5px 0 5px -6px #ccc; |
|
215 |
} |
|
216 |
|
|
217 |
:deep(.el-tabs__nav-prev) { |
|
218 |
font-size: 15px; |
|
219 |
line-height: 32px; |
|
220 |
box-shadow: 5px 0 5px -6px #ccc; |
|
221 |
} |
|
222 |
|
|
223 |
:deep(.el-input-group__append) { |
|
224 |
padding: 0; |
|
225 |
} |
|
226 |
|
|
227 |
:deep(.el-tabs__item) { |
|
228 |
height: 30px; |
|
229 |
font-size: 12px; |
|
230 |
font-weight: normal; |
|
231 |
line-height: 30px; |
|
232 |
} |
|
233 |
|
|
234 |
:deep(.el-tabs__header), |
|
235 |
:deep(.el-tabs__nav-wrap) { |
|
236 |
position: static; |
|
237 |
margin: 0; |
|
238 |
} |
|
239 |
</style> |