IconPicker.vue 2.36 KB
<script lang="ts" setup>
import { NInput, NInputGroup, NInputGroupLabel, NPopover, NScrollbar } from 'naive-ui';
import '@/assets/external/iconfont/iconfont.js'
import iconfont from '@/assets/external/iconfont/iconfont.json'
import SvgIcon from './SvgIcon.vue';
import { computed, ref, unref } from 'vue';
import { useDesignStore } from '@/store/modules/designStore/designStore';

const props = defineProps({
  value: {
    type: String,
  }
})

const emit = defineEmits(['update:value'])

const searchValue = ref<string>('')

const getIconList = computed(() => {
  const icons = iconfont.glyphs.map(item => item.font_class)
  const text = unref(searchValue)
  return icons.filter(icon => icon.includes(text))
})

const designStore = useDesignStore()

const themeColor = computed(() => {
  return designStore.getAppTheme
})

const handleChange = (icon: string) => {
  emit('update:value', icon)
}

</script>

<template>
  <NInputGroup class="icon-picker">
    <NInput :value="value" placeholder="请选择图标" disabled />
    <NPopover trigger="click">
      <NInput v-model:value="searchValue" size="small" style="text-overflow: ellipsis;" />
      <NScrollbar style="max-height: 120px; max-width: 210px; margin-top: 5px;">
        <ul class="icon-list">
          <li class="icon-item" v-for="icon in getIconList" :key="icon" @click="handleChange(icon)"
            :style="{ border: icon === props.value ? `1px solid ${themeColor}` : '' }">
            <SvgIcon :name="icon" prefix="iconfont" />
          </li>
        </ul>
      </NScrollbar>
      <template #trigger>
        <NInputGroupLabel style="cursor: pointer;">
          <SvgIcon :name="value || 'grid-one'" prefix="iconfont" style="cursor: pointer;" />
        </NInputGroupLabel>
      </template>
    </NPopover>
  </NInputGroup>
</template>

<style lang="scss" scoped>
.icon {
  &-picker {
    @include deep() {
      .n-input__input-el {
        text-overflow: ellipsis;
      }
    }
  }


  &-list {
    display: flex;
    list-style: none;
    padding: 0;
    justify-content: start;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
  }

  &-item {
    box-sizing: border-box;
    cursor: pointer;
    width: 35px;
    height: 35px;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: transform .5s linear;

    &:hover {
      border: 1px solid v-bind("themeColor");
    }
  }


}
</style>