vue3,naive图标库封装

在assets的icons下面建文件夹svg,svg下载地址如下:xicons - Icons for Vue & React

这里下载的是ionicons5的svg

requireIcons.ts

import type { Ref } from 'vue';
import { ref } from 'vue';

const icons: Ref<string[]> = ref([]);
const modules = import.meta.glob('./../../../../../assets/icons/svg/*.svg');
// eslint-disable-next-line guard-for-in
for (const path in modules) {
  const p = path.split('assets/icons/svg/')[1].split('.svg')[0];
  icons.value.push(p);
}

export default icons;

iconSelect.vue

<template>
  <div class="icon-body">
    <div class="icon-list">
      <div class="list-container">
        <div v-for="(item, index) in iconList" :key="index" class="icon-item-wrapper" @click="selectedIcon(item)">
          <div :class="['icon-item', { active: activeIcon === item }]">
            <svg-icon :icon-name="item" class-name="icon" style="height: 28px; width: 16px" />
            <span>{{ item }}</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import svgIcon from '../SvgIcon/index.vue';
import icons from './requireIcons';

defineProps({
  activeIcon: {
    type: String,
    default: ''
  }
});

const iconList = ref(icons);
const emit = defineEmits(['selected']);

function selectedIcon(name: string) {
  emit('selected', name);
  document.body.click();
}
</script>

<style lang="scss" scoped>
.icon-body {
  width: 100%;
  padding: 10px;
  .icon-search {
    position: relative;
    margin-bottom: 5px;
  }
  .icon-list {
    height: 200px;
    overflow: auto;
    .list-container {
      display: flex;
      flex-wrap: wrap;
      .icon-item-wrapper {
        width: calc(100% / 3);
        height: 25px;
        line-height: 25px;
        cursor: pointer;
        display: flex;
        .icon-item {
          display: flex;
          max-width: 100%;
          height: 100%;
          padding: 0 5px;
          &:hover {
            background: #ececec;
            border-radius: 5px;
          }
          .icon {
            flex-shrink: 0;
          }
          span {
            display: inline-block;
            vertical-align: -0.15em;
            fill: currentColor;
            padding-left: 2px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
          }
        }
        .icon-item.active {
          background: #ececec;
          border-radius: 5px;
        }
      }
    }
  }
}
</style>

svgIcon.vue

<template>
  <n-icon class="svg-icon" :component="icon" style="margin-top: 4px" />
</template>

<script setup lang="ts">
import type { Component } from 'vue';
import { shallowRef, defineProps, onMounted } from 'vue';
import * as icons from '@vicons/ionicons5';

const props = defineProps({
  iconName: {
    type: String,
    required: true
  },
  className: {
    type: String,
    default: ''
  },
  color: {
    type: String,
    default: ''
  }
});

const icon = shallowRef<Component>();

function getIconInfo() {
  icon.value = icons[props.iconName];
}

onMounted(() => {
  getIconInfo();
});
</script>

<style scope lang="scss">
.sub-el-icon,
.nav-icon {
  display: inline-block;
  font-size: 15px;
  margin-right: 12px;
  position: relative;
}

.svg-icon {
  width: 1em;
  height: 1em;
  position: relative;
  fill: currentColor;
  vertical-align: -2px;
}
</style>

展示界面

<n-form-item label="菜单图标" path="icon">
	<n-popover trigger="click" :show="showPopover" width="trigger" placement="bottom-start">
		<template #trigger>
			<n-input
				v-model:value="menuForm.icon"
				placeholder="点击选择图标"
				style="margin-bottom: 2px"
				@blur="showSelectIcon"
				@click="showSelectIcon"
			>
				<template #prefix>
					<!--如果是回显,则回显图标-->
					<svg-icon v-if="menuForm.icon" :icon-name="menuForm.icon" style="height: 22px; width: 16px" />
					<!--如果是新增,则显示下面图标-->
					<icon-uil-search v-else class="text-20px text-#c2c2c2" />
				</template>
			</n-input>
		</template>
		<icon-select ref="iconSelectRef" :active-icon="menuForm.icon" @selected="selected"></icon-select>
	</n-popover>
</n-form-item>

1.width="trigger" 使 popover 的宽度等于触发元素。

2.placement="bottom-start",弹出信息展示的方向。

3.<template #trigger<标签>/>,触发的方式

const showPopover = ref(false);
/** 展示下拉图标 */
function showSelectIcon() {
  showPopover.value = !showPopover.value;
}

/** 选择图标 */
function selected(name: string) {
  menuForm.icon = name;
  showPopover.value = false;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值