封装ElementPlusIcons图标和系统应用内置图片为应用图标

效果图:

文件放置位置结构

1、定义选择按钮父组件 icon

html 复制代码
<template>
  <div>
    <iconEdit :mode="'button'" />
  </div>
</template>
<script lang="ts" setup>
import iconEdit from "../../components/IconEdit/indev.vue";

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

2、IconEdit组件

html 复制代码
<template>
    <div>
      <div v-if="mode === 'button'" class="button-container">
        <IconComp v-if="icon" :icon="icon" />
        <el-button link type="primary" @click="openIcon"> 选择图片 </el-button>
      </div>
      <el-dialog v-model="iconVisible" title="选择图标" width="900" draggable :close-on-click-modal="false">
        <el-tabs v-model="activeName" class="icons-tabs">
          <el-tab-pane label="内置图标" name="icon">
            <div class="button-container">
              <el-input
                v-model="search"
                :suffix-icon="Search"
                placeholder="请输入关键字搜索图标"
                style="width: 240px"
                @input="searchAction(search)"
              />
              <el-input v-model="colorInput" style="width: 120px" placeholder="颜色">
                <template #suffix>
                  <input ref="iconPick" type="color" v-model="colorInput" class="w-[26px]" />
                </template>
              </el-input>
            </div>
            <div class="icons-container mt-3 h-[350px] overflow-y-auto">
              <el-row :gutter="20">
                <el-col
                  v-for="(item, index) in elementPlusIcons"
                  :key="index"
                  :span="2"
                  class="mb-1 cursor-pointer"
                  @click="selectAction(item.name)"
                >
                  <div :class="{ 'selected-icon': item.name === selected }">
                    <component :is="item" v-bind="$attrs" :style="{ color: colorInput }" />
                    <p class="icons-text text-center">{{ item.name }}</p>
                  </div>
                </el-col>
              </el-row>
            </div>
          </el-tab-pane>
  
          <el-tab-pane label="系统内置图片" name="icon-preset">
            <el-input
              v-model="search"
              :suffix-icon="Search"
              placeholder="请输入关键字搜索图片"
              style="width: 240px"
              @input="searchAction(search)"
            />
            <div class="icons-container mt-3 h-[350px] overflow-y-auto">
              <el-row :gutter="20">
                <el-col
                  v-for="(item, index) in systemIcons"
                  :key="index"
                  :span="2"
                  class="mb-1 cursor-pointer"
                  @click="selectAction(item.code)"
                >
                  <div
                    style="display: flex; align-items: center; flex-direction: column"
                    :class="{ 'selected-icon': item.code === selected }"
                  >
                    <img style="width: 50px; height: 50px" :src="item.icon" />
                    <p class="icons-text text-center">{{ item.name }}</p>
                  </div>
                </el-col>
              </el-row>
            </div>
          </el-tab-pane>
        </el-tabs>
        <template #footer>
          <div class="dialog-footer">
            <el-button @click="reset">重置</el-button>
            <el-button @click="iconVisible = false">取消</el-button>
            <el-button type="primary" @click="handleConfirm()"> 确定 </el-button>
          </div>
        </template>
      </el-dialog>
    </div>
  </template>
  
  <script lang="ts" setup>
  import { type Component, ref, shallowRef, watch, nextTick } from "vue";
  import IconComp from "../../components/IconEdit/iconComp.vue";
  import { Icons, AiIcons } from "../../assets/index";
  import { Search } from "@element-plus/icons-vue";
  import * as ElementPlusIcons from "@element-plus/icons-vue";
  
  const props = defineProps<{
    mode?: string;
    isReadonly?: boolean;
  }>();
  
  /** 数据源, 父组件不能为空,默认'' */
  const icon = defineModel("icon", {
    type: String,
    default: "",
  });
  
  const emit = defineEmits(["confirm", "typeConfirm"]);
  const activeName = ref("icon");
  const iconComp = shallowRef<Component>();
  const search = ref("");
  const colorInput = ref("");
  const selected = ref<string>("");
  const systemIcons = ref<any[]>([...Icons, ...AiIcons]);
  
  // 打开模态框
  const iconVisible = ref(false);
  const iconPick = ref();
  // 打开弹窗
  const openIcon = () => {
    iconVisible.value = true;
    search.value = "";
    const iconArray = icon.value.split("#");
    iconComp.value = ElementPlusIcons[iconArray[0] as keyof typeof ElementPlusIcons];
    if (iconComp.value) {
      selected.value = iconArray[0];
      colorInput.value = iconArray[1] ? `#${iconArray[1]}` : "";
      nextTick(() => {
        iconPick.value.value = colorInput.value;
      });
    }
    searchAction("");
  };
  // 关闭弹窗
  const closeIcon = () => {
    iconVisible.value = false;
  };
  const elementPlusIcons = shallowRef<any>(ElementPlusIcons);
  
  const reset = () => {
    selected.value = "";
    iconComp.value = undefined;
    colorInput.value = "";
    iconPick.value.value = "";
  };
  // 搜索图标
  const searchAction = (keyWord: string) => {
    if (keyWord === "") {
      elementPlusIcons.value = ElementPlusIcons;
      return;
    }
    const filterIcons = Object.keys(ElementPlusIcons).filter((item) => {
      return item.toLowerCase().includes(keyWord.toLowerCase());
    });
    elementPlusIcons.value = {};
    filterIcons.forEach((item) => {
      elementPlusIcons.value[item] = ElementPlusIcons[item as keyof typeof ElementPlusIcons];
    });
  };
  const selectAction = (item: string) => {
    selected.value = item;
  };
  // 确定图标
  const handleConfirm = () => {
    icon.value = activeName.value === "icon" && colorInput.value ? selected.value + colorInput.value : selected.value;
    emit("confirm", icon.value);
    emit("typeConfirm", {
      type: activeName,
      value: icon.value,
    });
    iconVisible.value = false;
  };
  
  watch(
    () => icon.value,
    (newValue) => {
      if (newValue) {
        const iconArray = newValue.split("#");
        iconComp.value = ElementPlusIcons[iconArray[0] as keyof typeof ElementPlusIcons];
        if (iconComp.value) {
          selected.value = iconArray[0];
          colorInput.value = iconArray[1];
          nextTick(() => {
            if (iconPick.value) iconPick.value.value = colorInput.value ? `#${colorInput.value}` : "";
          });
        }
      } else {
        selected.value = "";
        iconComp.value = undefined;
        colorInput.value = "";
      }
    },
    {
      immediate: true,
    }
  );
  
  // 暴露方法·
  defineExpose({
    closeIcon,
    openIcon,
  });
  </script>
  <style scoped lang="scss">
  .icons-tabs {
    .icons-container {
      padding-right: 15px;
      margin-right: -10px;
    }
  }
  
  .selected-icon {
    background-color: #409eff;
    border-radius: 6px;
  }
  
  .icons-text {
    font-size: 12px;
  }
  .button-container {
  display: flex;
  gap: 0.5rem; /* 2对应大约0.5rem(8px) */
}
  </style>
  

3、iconComp组件

html 复制代码
<template>
    <div>
      <component v-if="iconComp" :is="iconComp" :style="{ color: icon?.split('#')[1], width: size + 'px', height: size + 'px' }" />
      <img
        v-else-if="systemIcons?.find((f: any) => f.code == icon)"
         :style="{ width: size + 'px', height: size + 'px' }"
        :src="systemIcons?.find((f: any) => f.code == icon)?.icon"
      />
      <div v-else-if="icon" class="form-icon-item" v-html="icon"></div>
    </div>
  </template>
  
  <script setup lang="ts">
  import { watch, shallowRef, type Component } from "vue";
  import * as ElementPlusIcons from "@element-plus/icons-vue";
  import { AiIcons, Icons } from "../../assets/index";
  
  const props = defineProps({
    icon: {
      type: String,
      default: () => {},
    },
    size: {
      type: Number,
      default: 16,
    },
  });
  const systemIcons = [...Icons, ...AiIcons];
  const iconComp = shallowRef<Component>();
  
  watch(
    () => props.icon,
    (newValue) => {
      if (newValue) {
        const iconArray = newValue.split("#");
        iconComp.value = ElementPlusIcons[iconArray[0] as keyof typeof ElementPlusIcons];
      }
    },
    {
      immediate: true,
    }
  );
  </script>
  
  <style lang="less" scoped></style>
  

4、系统内置图片路径

index.ts

TypeScript 复制代码
import bbmbSrc from "../assets/aiToolsIcons/baobiaomoban.png";
import aizy from "../assets/aiToolsIcons/ocr-yinshuawenzishibie.png";
import wbrs from "../assets/aiToolsIcons/wenbenbianjitianchong.png";
import dybgzx from "../assets/aiToolsIcons/baogao.png";
import dyjhzd from "../assets/aiToolsIcons/jihua.png";
import wzsb from "../assets/aiToolsIcons/ocr-yinshuawenzishibie.png";
import wdxxtq from "../assets/aiToolsIcons/wendang.png";
import pzsb from "../assets/aiToolsIcons/chuanpiaozhengfuwu.png";
import wdzh from "../assets/aiToolsIcons/zhuanhuan.png";
import wjcfhb from "../assets/aiToolsIcons/picichaifenhebing.png";
import yywbsc from "../assets/aiToolsIcons/zhihuiyuyinwenben.png";
import hgxjc from "../assets/aiToolsIcons/hefahegui.png";
import bgzdhsc from "../assets/aiToolsIcons/baobiaomoban.png";
import hyjysc from "../assets/aiToolsIcons/huiyi.png";
import wzzyy from "../assets/aiToolsIcons/zhihuiyuyinwenben.png";
import csznzs from "../assets/aiToolsIcons/测试智能助手.png";
import flfg from "../assets/aiToolsIcons/法律法规.png";
import fgk from "../assets/aiToolsIcons/法规库.png";
import flfgk from "../assets/aiToolsIcons/法律法规库@2x.png";
import nbzdk from "../assets/aiToolsIcons/内部制度库.png";
import rdjdzs from "../assets/aiToolsIcons/人大监督助手@2x.png";
import sjfxjmzs from "../assets/aiToolsIcons/审计分析建模助手.png";
import sjjdzs from "../assets/aiToolsIcons/审计监督助手@2x.png";
import sjwtdxzs from "../assets/aiToolsIcons/审计问题定性助手.png";
import sjywtjzs from "../assets/aiToolsIcons/审计业务推荐助手.png";
import sjzgzyzs from "../assets/aiToolsIcons/审计整改指引助手.png";
import xzyszt from "../assets/aiToolsIcons/新增预设主题.png";
import zbdbfxznzs from "../assets/aiToolsIcons/招标对比分析智能助手.png";
import zmzcfxzs from "../assets/aiToolsIcons/中煤招采分析助手.png";
import zdytsc from "../assets/aiToolsIcons/自定义提示词@2x.png";
import aiyyzs from "../assets/aiToolsIcons/AI应用助手@2x.png";
import bijcfxzs from "../assets/aiToolsIcons/BI集成分析助手.png";

export * from './aiIcons/index';

export const Icons = [
    {
        name: '标签模板',
        code: 'system-bbmbSrc',
        icon: bbmbSrc
    },
    {
        name: '文字识别',
        code: 'system-aizy',
        icon: aizy
    },
    {
        name: '文本编辑',
        code: 'system-wbrs',

        icon: wbrs
    },
    {
        name: '报告',
        code: 'system-dybgzx',

        icon: dybgzx
    },
    {
        name: '计划',
        code: 'system-dyjhzd',

        icon: dyjhzd
    },
    {
        name: '识别',
        code: 'system-wzsb',

        icon: wzsb
    },
    {
        name: '文档',
        code: 'system-wdxxtq',

        icon: wdxxtq
    },
    {
        name: '传票',
        code: 'system-pzsb',

        icon: pzsb
    },
    {
        name: '转换',
        code: 'system-wdzh',

        icon: wdzh
    },
    {
        name: '拆分',
        code: 'system-wjcfhb',

        icon: wjcfhb
    }, {
        name: '语音',
        code: 'system-yywbsc',

        icon: yywbsc
    }, {
        name: '合法合规',
        code: 'system-hgxjc',

        icon: hgxjc
    }, {
        name: '报表模板',
        code: 'system-bgzdhsc',

        icon: bgzdhsc
    }, {
        name: '会议',
        code: 'system-hyjysc',

        icon: hyjysc
    }, {
        name: '语音文本',
        code: 'system-wzzyy',
        icon: wzzyy
    },
     {
        name: '测试智能助手',
        code: 'system-csznzs',
        icon: csznzs
    },
     {
        name: '法律法规',
        code: 'system-flfg',
        icon: flfg
    },
     {
        name: '法规库',
        code: 'system-fgk',
        icon: fgk
    },
     {
        name: '法律法规库',
        code: 'system-flfgk',
        icon: flfgk
     },
     {
        name: '内部制度库',
        code: 'system-nbzdk',
        icon: nbzdk
     },
     {
        name: '人大监督助手',
        code: 'system-rdjdzs',
        icon: rdjdzs
     },
     {
        name: '审计分析建模助手',
        code: 'system-sjfxjmzs',
        icon: sjfxjmzs
     },
     {
        name: '审计监督助手',
        code: 'system-sjjdzs',
        icon: sjjdzs
     },
     {
        name: '审计问题定性助手',
        code: 'system-sjwtdxzs',
        icon: sjwtdxzs
     },
     {
        name: '审计业务推荐助手',
        code: 'system-sjywtjzs',
        icon: sjywtjzs
     },
     {
        name: '审计整改指引助手',
        code: 'system-sjzgzyzs',
        icon: sjzgzyzs
     },
     {
        name: '新增预设主题',
        code: 'system-xzyszt',
        icon: xzyszt
     },
     {
        name: '招标对比分析智能助手',
        code: 'system-zbdbfxznzs',
        icon: zbdbfxznzs
     },
     {
        name: '中煤招采分析助手',
        code: 'system-zmzcfxzs',
        icon: zmzcfxzs
     },
     {
        name: '自定义提示词',
        code: 'system-zdytsc',
        icon: zdytsc
     },
     {
        name: 'AI应用助手',
        code: 'system-aiyyzs',
        icon: aiyyzs
     },
     {
        name: 'BI集成分析助手',
        code: 'system-bijcfxzs',
        icon: bijcfxzs
     },


]
相关推荐
JELEE.6 小时前
Vue3复习笔记
vue.js·笔记·vue
by__csdn8 小时前
第二章 (.NET Core环境搭建)第二节( Visual Studio Code)
ide·vscode·c#·vue·asp.net·.net·.netcore
是梦终空9 小时前
JAVA毕业设计253—基于Java+Springboot+vue3+协同过滤推荐算法的传统服饰文化平台(源代码+数据库+任务书+12000字论文)
java·spring boot·vue·毕业设计·课程设计·协同过滤推荐算法·传统服饰文化平台
水宁成冰1 天前
前端静态网站Lighthouse评分优化,vue3项目
前端·vue
前端无涯1 天前
TypeScript 完整学习指南:从基础到工程化实践
typescript·vue·react
邂逅星河浪漫1 天前
【Dify-Chatflow】简历优化助手实现+前后端分离式系统集成+Docker容器化部署)
java·docker·vue·springboot·dify·apifox
by__csdn1 天前
Vue3 大文件分片上传完整指南:图片/视频附件高效传输方案
前端·javascript·vue.js·typescript·vue·css3·html5
gzmyh1 天前
thinkphp8+vue3整合的工作流实战demo
vue·php·workflow·工作流
离别又见离别2 天前
vue使用js渲染组件案例(公用打印组件动态渲染)及静默打印实现
前端·javascript·vue