|
|
@ -7,7 +7,7 @@ |
|
|
v-model:value="currentSelect" |
|
|
v-model:value="currentSelect" |
|
|
> |
|
|
> |
|
|
<template #addonAfter> |
|
|
<template #addonAfter> |
|
|
<Popover |
|
|
<a-popover |
|
|
placement="bottomLeft" |
|
|
placement="bottomLeft" |
|
|
trigger="click" |
|
|
trigger="click" |
|
|
v-model="visible" |
|
|
v-model="visible" |
|
|
@ -17,7 +17,7 @@ |
|
|
<div class="flex justify-between"> |
|
|
<div class="flex justify-between"> |
|
|
<a-input |
|
|
<a-input |
|
|
:placeholder="t('component.icon.search')" |
|
|
:placeholder="t('component.icon.search')" |
|
|
@change="handleSearchChange" |
|
|
@change="debounceHandleSearchChange" |
|
|
allowClear |
|
|
allowClear |
|
|
/> |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
@ -53,7 +53,7 @@ |
|
|
</ul> |
|
|
</ul> |
|
|
</ScrollContainer> |
|
|
</ScrollContainer> |
|
|
<div class="flex py-2 items-center justify-center" v-if="getTotal >= pageSize"> |
|
|
<div class="flex py-2 items-center justify-center" v-if="getTotal >= pageSize"> |
|
|
<Pagination |
|
|
<a-pagination |
|
|
showLessItems |
|
|
showLessItems |
|
|
size="small" |
|
|
size="small" |
|
|
:pageSize="pageSize" |
|
|
:pageSize="pageSize" |
|
|
@ -63,7 +63,7 @@ |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<template v-else |
|
|
<template v-else |
|
|
><div class="p-5"><Empty /></div> |
|
|
><div class="p-5"><a-empty /></div> |
|
|
</template> |
|
|
</template> |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
@ -71,16 +71,14 @@ |
|
|
<SvgIcon :name="currentSelect" /> |
|
|
<SvgIcon :name="currentSelect" /> |
|
|
</span> |
|
|
</span> |
|
|
<Icon :icon="currentSelect || 'ion:apps-outline'" class="cursor-pointer px-2 py-1" v-else /> |
|
|
<Icon :icon="currentSelect || 'ion:apps-outline'" class="cursor-pointer px-2 py-1" v-else /> |
|
|
</Popover> |
|
|
</a-popover> |
|
|
</template> |
|
|
</template> |
|
|
</a-input> |
|
|
</a-input> |
|
|
</template> |
|
|
</template> |
|
|
<script lang="ts"> |
|
|
<script lang="ts" setup> |
|
|
import { defineComponent, ref, watchEffect, watch, unref } from 'vue'; |
|
|
import { ref, watchEffect, watch, unref } from 'vue'; |
|
|
|
|
|
|
|
|
import { useDesign } from '/@/hooks/web/useDesign'; |
|
|
import { useDesign } from '/@/hooks/web/useDesign'; |
|
|
import { ScrollContainer } from '/@/components/Container'; |
|
|
import { ScrollContainer } from '/@/components/Container'; |
|
|
|
|
|
|
|
|
import { Input, Popover, Pagination, Empty } from 'ant-design-vue'; |
|
|
import { Input, Popover, Pagination, Empty } from 'ant-design-vue'; |
|
|
import Icon from './Icon.vue'; |
|
|
import Icon from './Icon.vue'; |
|
|
import SvgIcon from './SvgIcon.vue'; |
|
|
import SvgIcon from './SvgIcon.vue'; |
|
|
@ -94,6 +92,12 @@ |
|
|
import { useMessage } from '/@/hooks/web/useMessage'; |
|
|
import { useMessage } from '/@/hooks/web/useMessage'; |
|
|
import svgIcons from 'virtual:svg-icons-names'; |
|
|
import svgIcons from 'virtual:svg-icons-names'; |
|
|
|
|
|
|
|
|
|
|
|
// 没有使用别名引入,是因为WebStorm当前版本还不能正确识别,会报unused警告 |
|
|
|
|
|
const AInput = Input; |
|
|
|
|
|
const APopover = Popover; |
|
|
|
|
|
const APagination = Pagination; |
|
|
|
|
|
const AEmpty = Empty; |
|
|
|
|
|
|
|
|
function getIcons() { |
|
|
function getIcons() { |
|
|
const data = iconsData as any; |
|
|
const data = iconsData as any; |
|
|
const prefix: string = data?.prefix ?? ''; |
|
|
const prefix: string = data?.prefix ?? ''; |
|
|
@ -110,88 +114,70 @@ |
|
|
return svgIcons.map((icon) => icon.replace('icon-', '')); |
|
|
return svgIcons.map((icon) => icon.replace('icon-', '')); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export default defineComponent({ |
|
|
const props = defineProps({ |
|
|
name: 'IconPicker', |
|
|
value: propTypes.string, |
|
|
components: { [Input.name]: Input, Icon, Popover, ScrollContainer, Pagination, Empty, SvgIcon }, |
|
|
width: propTypes.string.def('100%'), |
|
|
inheritAttrs: false, |
|
|
pageSize: propTypes.number.def(140), |
|
|
props: { |
|
|
copy: propTypes.bool.def(false), |
|
|
value: propTypes.string, |
|
|
mode: propTypes.oneOf<('svg' | 'iconify')[]>(['svg', 'iconify']).def('iconify'), |
|
|
width: propTypes.string.def('100%'), |
|
|
}); |
|
|
pageSize: propTypes.number.def(140), |
|
|
|
|
|
copy: propTypes.bool.def(false), |
|
|
const emit = defineEmits(['change', 'update:value']); |
|
|
mode: propTypes.oneOf<('svg' | 'iconify')[]>(['svg', 'iconify']).def('iconify'), |
|
|
|
|
|
|
|
|
const isSvgMode = props.mode === 'svg'; |
|
|
|
|
|
const icons = isSvgMode ? getSvgIcons() : getIcons(); |
|
|
|
|
|
|
|
|
|
|
|
const currentSelect = ref(''); |
|
|
|
|
|
const visible = ref(false); |
|
|
|
|
|
const currentList = ref(icons); |
|
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n(); |
|
|
|
|
|
const { prefixCls } = useDesign('icon-picker'); |
|
|
|
|
|
|
|
|
|
|
|
const debounceHandleSearchChange = useDebounceFn(handleSearchChange, 100); |
|
|
|
|
|
const { clipboardRef, isSuccessRef } = useCopyToClipboard(props.value); |
|
|
|
|
|
const { createMessage } = useMessage(); |
|
|
|
|
|
|
|
|
|
|
|
const { getPaginationList, getTotal, setCurrentPage } = usePagination( |
|
|
|
|
|
currentList, |
|
|
|
|
|
props.pageSize, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
watchEffect(() => { |
|
|
|
|
|
currentSelect.value = props.value; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
watch( |
|
|
|
|
|
() => currentSelect.value, |
|
|
|
|
|
(v) => { |
|
|
|
|
|
emit('update:value', v); |
|
|
|
|
|
return emit('change', v); |
|
|
}, |
|
|
}, |
|
|
emits: ['change', 'update:value'], |
|
|
); |
|
|
setup(props, { emit }) { |
|
|
|
|
|
const isSvgMode = props.mode === 'svg'; |
|
|
|
|
|
const icons = isSvgMode ? getSvgIcons() : getIcons(); |
|
|
|
|
|
|
|
|
|
|
|
const currentSelect = ref(''); |
|
|
|
|
|
const visible = ref(false); |
|
|
|
|
|
const currentList = ref(icons); |
|
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n(); |
|
|
|
|
|
const { prefixCls } = useDesign('icon-picker'); |
|
|
|
|
|
|
|
|
|
|
|
const debounceHandleSearchChange = useDebounceFn(handleSearchChange, 100); |
|
|
|
|
|
const { clipboardRef, isSuccessRef } = useCopyToClipboard(props.value); |
|
|
|
|
|
const { createMessage } = useMessage(); |
|
|
|
|
|
|
|
|
|
|
|
const { getPaginationList, getTotal, setCurrentPage } = usePagination( |
|
|
|
|
|
currentList, |
|
|
|
|
|
props.pageSize, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
watchEffect(() => { |
|
|
|
|
|
currentSelect.value = props.value; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
watch( |
|
|
|
|
|
() => currentSelect.value, |
|
|
|
|
|
(v) => { |
|
|
|
|
|
emit('update:value', v); |
|
|
|
|
|
return emit('change', v); |
|
|
|
|
|
}, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
function handlePageChange(page: number) { |
|
|
|
|
|
setCurrentPage(page); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function handleClick(icon: string) { |
|
|
function handlePageChange(page: number) { |
|
|
currentSelect.value = icon; |
|
|
setCurrentPage(page); |
|
|
if (props.copy) { |
|
|
} |
|
|
clipboardRef.value = icon; |
|
|
|
|
|
if (unref(isSuccessRef)) { |
|
|
|
|
|
createMessage.success(t('component.icon.copy')); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function handleSearchChange(e: ChangeEvent) { |
|
|
function handleClick(icon: string) { |
|
|
const value = e.target.value; |
|
|
currentSelect.value = icon; |
|
|
if (!value) { |
|
|
if (props.copy) { |
|
|
setCurrentPage(1); |
|
|
clipboardRef.value = icon; |
|
|
currentList.value = icons; |
|
|
if (unref(isSuccessRef)) { |
|
|
return; |
|
|
createMessage.success(t('component.icon.copy')); |
|
|
} |
|
|
|
|
|
currentList.value = icons.filter((item) => item.includes(value)); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return { |
|
|
function handleSearchChange(e: ChangeEvent) { |
|
|
t, |
|
|
const value = e.target.value; |
|
|
prefixCls, |
|
|
if (!value) { |
|
|
visible, |
|
|
setCurrentPage(1); |
|
|
isSvgMode, |
|
|
currentList.value = icons; |
|
|
getTotal, |
|
|
return; |
|
|
getPaginationList, |
|
|
} |
|
|
handlePageChange, |
|
|
currentList.value = icons.filter((item) => item.includes(value)); |
|
|
handleClick, |
|
|
} |
|
|
currentSelect, |
|
|
|
|
|
handleSearchChange: debounceHandleSearchChange, |
|
|
|
|
|
}; |
|
|
|
|
|
}, |
|
|
|
|
|
}); |
|
|
|
|
|
</script> |
|
|
</script> |
|
|
<style lang="less"> |
|
|
<style lang="less"> |
|
|
@prefix-cls: ~'@{namespace}-icon-picker'; |
|
|
@prefix-cls: ~'@{namespace}-icon-picker'; |
|
|
|