vue3+element-plus实现图标选择器

见题知意,效果如下所示:

在这里插入图片描述
在这里插入图片描述
如上所示,该组件有两种模式,分别为输入框模式(input)及按钮模式(button),可根据不同的需求传入相应的模式参数。

具体代码如下:

<template>
  <div class="icon-select-container relative" :style="{ width }">
    <el-input
      v-if="type === 'input'"
      v-model="selectValue"
      placeholder="点击选择图标"
      v-click-outside="clickOutside"
      readonly
      ref="selectRef"
    >
      <template #prepend>
        <svg-icon :name="selectValue" />
      </template>
    </el-input>
    <el-button v-else v-click-outside="clickOutside" ref="selectRef">
      <svg-icon :name="selectValue" />
      <span class="ml-4px">{{ selectValue || '点击选择图标' }}</span>
    </el-button>
    <el-popover
      shadow="none"
      ref="popoverRef"
      :virtual-ref="selectRef"
      virtual-triggering
      placement="bottom-end"
      trigger="click"
      :teleported="false"
      :width="width"
    >
      <el-input v-model="searchValue" placeholder="输入名称搜索图标" />
      <el-divider border-style="dashed" />
      <el-scrollbar :height="scrollbarHeight">
        <ul class="icon-list m-0 pl-10px">
          <template v-for="icon in filterIcons" :key="icon">
            <el-tooltip effect="dark" :content="icon" placement="top">
              <li
                class="icon-item p-5px mr-10px mb-10px w-10% cursor-pointer"
                @click="selectIcon(icon)"
              >
                <svg-icon :name="icon" />
              </li>
            </el-tooltip>
          </template>
        </ul>
      </el-scrollbar>
    </el-popover>
  </div>
</template>

<script setup lang="ts">
import { ClickOutside as vClickOutside } from 'element-plus';

defineOptions({
  name: 'iconSelect',
});

const prop = withDefaults(
  defineProps<{
    modelValue: string;
    type?: 'input' | 'button'; // 选择元素类型
    width?: string; // 容器宽度
    scrollbarHeight?: string; // 滚动高度
  }>(),
  {
    type: 'input',
    width: '100%',
    scrollbarHeight: '200px',
  }
);
const emit = defineEmits(['update:modelValue']);

// useVModel 为 vueuse中封装的hook,强烈推荐使用vueuse
const selectValue = useVModel(prop, 'modelValue', emit);
const selectRef = ref();
const searchValue = ref('');
const popoverRef = ref();

// 点击其它区域隐藏 popover 弹窗
function clickOutside() {
  unref(popoverRef).popperRef?.delayHide?.();
}

// 加载所有svg图标
const icons: string[] = [];
function loadIcons() {
  const svgs = import.meta.glob('../assets/svgs/*.svg');
  for (const icon in svgs) {
    const iconName = icon.split('assets/svgs/')[1].split('.svg')[0];
    icons.push(iconName);
  }
}
loadIcons();

const filterIcons = computed(() =>
  icons.filter((item) => item.includes(searchValue.value))
);
// 选则图标
function selectIcon(icon: string) {
  selectValue.value = icon;
  popoverRef.value?.hide();
  searchValue.value = '';
}
</script>

<style lang="scss" scoped>
.icon-list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;

  .icon-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-items: center;
    border: 1px solid #ccc;

    &:hover {
      color: var(--el-color-primary);
      border-color: var(--el-color-primary);
      transition: all 0.2s;
      transform: scaleX(1.1);
    }
  }
}
</style>

代码中类名的书写像 relative、mr-10px等等结尾css原子化写法,代码中其依赖包为 unocss

使用示例

<template>
  <div class="text-20px">
    <icon-select
      v-model="iconStr"
      width="520px"
      type="button"
      class="my-10px"
    />
    <icon-select v-model="iconStr" width="520px" />
  </div>
</template>

<script setup lang="ts">
// 图标选择
const iconStr = ref();
</script>

<style lang="scss" scoped></style>

更多详情可以查看项目在线地址,更希望能共同开发为这个项目添加各种功能,有意者可留言联系

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Vue 3.0+Element-Plus开发后台管理系统的步骤: 1.首先,确保你已经安装了Node.js和npm包管理器。 2.使用以下命令安装Vue CLI 4: ```shell npm install -g @vue/cli ``` 3.使用Vue CLI创建一个新项目: ```shell vue create my-project ``` 4.在创建项目时,选择使用Vue 3.0版本,并启用class-style component语法: ```shell ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, Router, Vuex, CSS Pre-processors, Linter, Unit ? Choose a version of Vue.js that you want to start the project with 3.x (Preview) ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? No ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass) ? Pick a linter / formatter config: ESLint with error prevention only ? Pick additional lint features: Lint on save ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files ``` 5.安装Element-Plus和Echarts 5.0: ```shell npm install element-plus echarts@5.0 ``` 6.在main.js中引入Element-Plus和Echarts: ```javascript import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' import ElementPlus from 'element-plus' import 'element-plus/lib/theme-chalk/index.css' import echarts from 'echarts' const app = createApp(App) app.use(store) app.use(router) app.use(ElementPlus) app.config.globalProperties.$echarts = echarts app.mount('#app') ``` 7.现在你可以开始使用Element-Plus和Echarts来开发你的后台管理系统了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值