潘志宝
6 天以前 ca22cdd5550cfa0defb0f430c538698182cdaec1
提交 | 用户 | 时间
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>