Files
vue-element-plus-admin/src/components/IconPicker/src/IconPicker.vue
2024-01-06 15:25:03 +08:00

194 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import epIcons from './data/icons.ep'
import antIcons from './data/icons.ant-design'
import tIcons from './data/icons.tdesign'
import { useDesign } from '@/hooks/web/useDesign'
import { ElInput, ElPopover, ElScrollbar, ElTabs, ElTabPane, ElPagination } from 'element-plus'
import { useAppStore } from '@/store/modules/app'
import { computed, CSSProperties, ref, unref, watch } from 'vue'
import { nextTick } from 'vue'
const init = async (icon?: string) => {
if (!icon) return
const iconInfo = icon.split(':')
iconName.value = iconInfo[0]
const wrapIndex = icons.findIndex((item) => item.prefix === iconInfo[0])
// 查询当前icon的索引
const index = filterItemIcons(icons[wrapIndex].icons).findIndex((item) => item === icon)
// 计算当前icon的页码
await nextTick()
currentPage.value = Math.ceil((index + 1) / unref(pageSize))
}
const modelValue = defineModel<string>()
const appStore = useAppStore()
const size = computed(() => appStore.getCurrentSize)
const iconSize = computed(() => {
return unref(size) === 'small'
? 'var(--el-component-size-small)'
: unref(size) === 'large'
? 'var(--el-component-size-large)'
: 'var(--el-component-size)'
})
const iconWrapStyle = computed((): CSSProperties => {
return {
width: unref(iconSize),
height: unref(iconSize),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 0 0 1px var(--el-input-border-color,var(--el-border-color)) inset',
position: 'relative',
left: '-1px',
cursor: 'pointer'
}
})
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('icon-picker')
const icons = [epIcons, antIcons, tIcons]
const iconName = ref(icons[0].prefix)
const currentIconNameIndex = computed(() => {
return icons.findIndex((item) => item.prefix === unref(iconName))
})
const tabChange = () => {
currentPage.value = 1
}
const pageSize = ref(49)
const currentPage = ref(1)
const filterIcons = (icons: string[]) => {
const start = (unref(currentPage) - 1) * unref(pageSize)
const end = unref(currentPage) * unref(pageSize)
return icons.slice(start, end)
}
watch(
() => modelValue.value,
async (val) => {
await nextTick()
val && init(val)
},
{
immediate: true
}
)
const popoverShow = () => {
init(unref(modelValue))
}
const iconSelect = (icon: string) => {
// 如果是同一个icon则不做处理则相当于点击了清空按钮
if (icon === unref(modelValue)) {
modelValue.value = ''
return
}
modelValue.value = icon
}
const search = ref('')
const filterItemIcons = (icons: string[]) => {
return icons.filter((item) => item.includes(unref(search)))
}
const inputClear = () => {
init(unref(modelValue))
}
</script>
<template>
<div :class="prefixCls" class="flex justify-center items-center box">
<ElInput disabled v-model="modelValue" clearable />
<ElPopover
placement="bottom"
trigger="click"
:width="450"
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; height: 380px;"
@show="popoverShow"
>
<template #reference>
<div :style="iconWrapStyle">
<Icon v-if="modelValue" :icon="modelValue" />
</div>
</template>
<ElScrollbar class="h-[calc(100%-50px)]!">
<ElInput
v-model="search"
class="mb-20px"
clearable
placeholder="搜索图标"
@clear="inputClear"
/>
<ElTabs tab-position="left" v-model="iconName" @tab-change="tabChange">
<ElTabPane v-for="item in icons" :key="item.name" :label="item.name" :name="item.prefix">
<div class="flex flex-wrap box-border">
<div
v-for="icon in filterIcons(filterItemIcons(item.icons))"
:key="icon"
:style="{
width: iconSize,
height: iconSize,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
border: `1px solid ${
icon === modelValue ? 'var(--el-color-primary)' : 'var(--el-border-color)'
}`,
boxSizing: 'border-box',
margin: '2px',
transition: 'all 0.3s'
}"
class="hover:border-color-[var(--el-color-primary)]!"
@click="iconSelect(icon)"
>
<Icon
:icon="icon"
:color="icon === modelValue ? 'var(--el-color-primary)' : 'inherit'"
/>
</div>
</div>
</ElTabPane>
</ElTabs>
</ElScrollbar>
<div
class="h-50px absolute bottom-0 left-0 flex items-center pl-[var(--el-popover-padding)] pr-[var(--el-popover-padding)]"
>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:pager-count="5"
small
:page-sizes="[100, 200, 300, 400]"
layout="total, prev, pager, next, jumper"
:total="filterItemIcons(icons[currentIconNameIndex].icons).length"
/>
</div>
</ElPopover>
</div>
</template>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-icon-picker';
.@{prefix-cls} {
:deep(.@{elNamespace}-input__wrapper) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
</style>