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