企业协同办公系统(OA)-【图标选择器】模块开发详解

企业协同办公系统(OA)-【图标选择器】模块开发详解

1. 功能需求

图标选择器是系统功能设置模块中的一个重要组件,用于为各种系统功能选择合适的图标。其主要功能需求如下:

  • 双模式图标选择:支持Font Awesome字体图标和系统符号图标(Emoji)两种类型
  • 图标搜索过滤:提供搜索功能,根据图标名称快速过滤显示结果
  • 颜色选择:支持为Font Awesome图标选择不同颜色
  • 图标预览:实时预览选中的图标及其应用颜色后的效果
  • 模态框交互:以模态框形式展示,提供清晰的选择界面
  • 响应式设计:适配不同屏幕尺寸的显示需求
  • 集成性:与系统功能表单无缝集成,支持图标数据的双向绑定

2. 第三方字体库介绍

本图标选择器主要依赖Font Awesome字体库:

Font Awesome

  • 版本 :4.x (通过fas fa-*类名判断)
  • 类型:矢量图标库
  • 主要用途:提供丰富的可缩放图标,支持自定义颜色和大小
  • 特点
    • 轻量级,加载速度快
    • 支持CSS样式自定义(颜色、大小、阴影等)
    • 图标数量丰富,覆盖多种应用场景
    • 支持响应式设计
  • 引用方式 :通过CSS类名直接引用,如<i class="fas fa-home"></i>

3. 功能运行流程图

flowchart TD A[开始] --> B[打开图标选择器模态框] B --> C[选择图标类型 Font Awesome系统符号] C --> D{输入搜索关键词} D -->|是| E[过滤图标列表] D -->|否| F[显示全部图标] E --> G F --> G G{选择图标颜色仅Font Awesome支持} G -->|是| H[应用选择的颜色] G -->|否| I[保持默认颜色] H --> J I --> J J[选择目标图标] --> K{点击确认按钮} K -->|是| L[保存选择结果] K -->|否| M[点击取消按钮] L --> N[关闭模态框] M --> N N --> O[结束]

运行效果

系统图标
字体图标
字体图标颜色切换

选择图标后点击确定进行文本框图标名称、颜色赋值,并显示选定图标

4. 功能实现分步拆解及源代码

4.1 界面结构设计

HTML模板(system_function_setting.html)
html 复制代码
<!-- 图标选择器模态框 -->
<div id="iconSelectorModal" class="icon-selector-modal" ref="iconSelectorModal">
    <div class="icon-selector-content">
        <!-- 搜索和模式切换容器 -->
        <div class="icon-color-selection" style="margin-top: 0; display: flex; align-items: flex-start; justify-content: left; gap: 15px; height: 40px; line-height: 40px;">
            <div class="icon-selector-header" style="margin: 0;">
                <h3 style="margin: 0;">请选择图标</h3>
            </div>
            <div style="display: flex; gap: 5px;">
                <button class="btn btn-secondary" :class="{ active: iconDisplayMode === 'system' }" @click="switchToSystemIcons" style="padding: 10px;">
                    <i class="fas fa-icons"></i> 系统图标
                </button>
                <button class="btn btn-secondary" :class="{ active: iconDisplayMode === 'fontawesome' }" @click="switchToFontAwesomeIcons" style="margin-right: 5px; padding: 10px;">
                    <i class="fas fa-font"></i> 字体图标
                </button>
            </div>
            <div class="icon-search" style="flex: 1; min-width: 200px; position: relative;">
                <i class="fas fa-search" style="position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: #999;"></i>
                <input type="text" v-model="iconSearchTerm" placeholder="搜索图标..." @input="filterIcons" style="padding-left: 30px; width: 100%; box-sizing: border-box;">
            </div>
        </div>
        <!-- 颜色选择区域 -->
        <div class="icon-color-selection" style="margin-top: 0.5px; display: flex; align-items: center; justify-content: left; gap: 15px; height: 40px; line-height: 40px;">
            <div class="icon-selector-header" style="margin: 0;">
                <h3 style="margin: 0;">请选择颜色</h3>
            </div>
            <div class="color-options" style="display: flex; gap: 5px;">
                <button v-for="color in colorOptions" :key="color.value" class="color-option" :class="{ selected: selectedColor === color.value }" :style="{ backgroundColor: color.value === 'white' ? '#fff' : color.value, color: color.value === 'white' ? '#000' : '#fff' }" @click="selectedColor = color.value" :disabled="iconDisplayMode === 'system'">
                    {{ color.name }}
                </button>
            </div>
        </div>
        <!-- 图标网格展示 -->
        <div class="icon-grid">
            <!-- Font Awesome图标展示 -->
            <div v-if="iconDisplayMode === 'fontawesome'" v-for="icon in filteredIcons" :key="icon.class" class="icon-item" :class="{ selected: selectedIcon === icon.class }" @click="selectIcon(icon.class)">
                <i :class="icon.class" class="icon-preview" :style="{ color: selectedColor }"></i>
                <span class="icon-name">{{ icon.name }}</span>
            </div>
            <!-- 系统符号图标展示 -->
            <div v-else v-for="icon in filteredIcons" :key="icon.key" class="icon-item" :class="{ selected: selectedIcon === icon.value }" @click="selectIcon(icon.value)">
                <span class="icon-preview" style="color: black; font-size: 20px;">{{ icon.value }}</span>
                <span class="icon-name">{{ icon.name }}</span>
            </div>
        </div>
        <!-- 底部操作按钮 -->
        <div class="icon-selector-footer">
            <button class="btn btn-secondary" @click="hideIconSelector"><i class="fas fa-times"></i> 取消</button>
            <button class="btn btn-primary" @click="confirmIconSelection"><i class="fas fa-check"></i> 确定</button>
        </div>
    </div>
</div>
CSS样式(system_function_setting.html)
css 复制代码
/* 图标选择器模态框 */
.icon-selector-modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 1000;
  overflow: auto;
}

/* 图标选择器内容 */
.icon-selector-content {
  background-color: #fefefe;
  margin: 5% auto;
  padding: 20px;
  border: 1px solid #888;
  width: 80%;
  max-width: 800px;
  max-height: 80vh;
  overflow-y: auto;
  border-radius: 8px;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}

/* 图标选择器头部 */
.icon-selector-header {
  margin-bottom: 15px;
}

.icon-selector-header h3 {
  margin: 0;
  font-size: 18px;
  color: #333;
}

/* 图标网格 */
.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 10px;
  margin: 20px 0;
  max-height: 400px;
  overflow-y: auto;
}

/* 图标项 */
.icon-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.icon-item:hover {
  border-color: #007bff;
  background-color: #f8f9fa;
}

.icon-item.selected {
  border-color: #007bff;
  background-color: #e3f2fd;
}

/* 图标预览 */
.icon-preview {
  font-size: 24px;
  margin-bottom: 5px;
}

/* 图标名称 */
.icon-name {
  font-size: 12px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* 图标选择器底部 */
.icon-selector-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}

4.2 数据模型设计

图标数据定义(icon_selector.js)
javascript 复制代码
// Font Awesome图标列表
window.commonIcons = [
  // 导航图标
  { class: 'fas fa-home', name: 'home' },
  { class: 'fas fa-directions', name: 'directions' },
  { class: 'fas fa-map-signs', name: 'map-signs' },
  { class: 'fas fa-compass', name: 'compass' },
  
  // 用户相关图标
  { class: 'fas fa-user', name: 'user' },
  { class: 'fas fa-users', name: 'users' },
  { class: 'fas fa-user-plus', name: 'user-plus' },
  { class: 'fas fa-user-minus', name: 'user-minus' },
  
  // 工具和设置图标
  { class: 'fas fa-cog', name: 'cog' },
  { class: 'fas fa-tools', name: 'tools' },
  { class: 'fas fa-wrench', name: 'wrench' },
  
  // 更多图标...
];

// 系统符号图标映射
window.iconMap = {
  'home': '🏠',
  'user': '👤',
  'users': '👥',
  'folder': '📁',
  'folder-open': '📂',
  'file': '📄',
  'search': '🔍',
  'edit': '✏️',
  'trash-alt': '🗑️',
  'save': '💾',
  'plus': '➕',
  'minus': '➖',
  'times': '❌',
  'check': '✅',
  // 更多图标映射...
};

// 颜色选项
window.colorOptions = [
  { name: '黑色', value: 'black' },
  { name: '白色', value: 'white' },
  { name: '蓝色', value: 'blue' },
  { name: '红色', value: 'red' },
  { name: '绿色', value: 'green' },
  { name: '紫色', value: 'purple' },
  { name: '橙色', value: 'orange' }
];

4.3 核心功能实现

Vue组件实现(system_function_setting.html)
javascript 复制代码
// 图标选择器相关变量
const iconSelectorModal = ref(null);
const iconDisplayMode = ref('fontawesome'); // 'fontawesome' or 'system'
const iconSearchTerm = ref('');
const filteredIcons = ref([]);
const selectedIcon = ref('');
const selectedColor = ref('black');

// 从全局对象获取图标数据
const commonIcons = window.commonIcons || [];
const iconMap = window.iconMap || {};
const colorOptions = window.colorOptions || [
  { name: '黑色', value: 'black' },
  { name: '白色', value: 'white' },
  { name: '蓝色', value: 'blue' },
  { name: '红色', value: 'red' },
  { name: '绿色', value: 'green' },
  { name: '紫色', value: 'purple' },
  { name: '橙色', value: 'orange' }
];

// 初始化图标列表
onMounted(() => {
  filteredIcons.value = [...commonIcons];
});

// 显示图标选择器
const showIconSelector = () => {
  if (iconSelectorModal.value) {
    iconSelectorModal.value.style.display = 'block';
    // 重置选择状态
    iconDisplayMode.value = 'fontawesome';
    iconSearchTerm.value = '';
    filteredIcons.value = [...commonIcons];
    selectedColor.value = 'black';
    
    // 如果已有选中图标,保持选择状态
    if (functionForm.icon) {
      selectedIcon.value = functionForm.icon;
    } else {
      selectedIcon.value = '';
    }
  }
};

// 隐藏图标选择器
const hideIconSelector = () => {
  if (iconSelectorModal.value) {
    iconSelectorModal.value.style.display = 'none';
  }
};

// 切换到系统图标
const switchToSystemIcons = () => {
  iconDisplayMode.value = 'system';
  
  // 转换系统图标格式
  const systemIcons = Object.entries(iconMap).map(([key, value]) => ({
    key: key,
    value: value,
    name: key
  }));
  
  filteredIcons.value = systemIcons;
  
  // 清空搜索词
  iconSearchTerm.value = '';
  
  // 重置选择状态
  selectedIcon.value = '';
};

// 切换到Font Awesome图标
const switchToFontAwesomeIcons = () => {
  iconDisplayMode.value = 'fontawesome';
  filteredIcons.value = [...commonIcons];
  
  // 清空搜索词
  iconSearchTerm.value = '';
  
  // 重置选择状态
  selectedIcon.value = '';
};

// 过滤图标
const filterIcons = () => {
  if (!iconSearchTerm.value) {
    if (iconDisplayMode.value === 'fontawesome') {
      filteredIcons.value = [...commonIcons];
    } else {
      const systemIcons = Object.entries(iconMap).map(([key, value]) => ({
        key: key,
        value: value,
        name: key
      }));
      filteredIcons.value = systemIcons;
    }
    return;
  }
  
  const searchTerm = iconSearchTerm.value.toLowerCase();
  
  if (iconDisplayMode.value === 'fontawesome') {
    filteredIcons.value = commonIcons.filter(icon =>
      icon.name.toLowerCase().includes(searchTerm)
    );
  } else {
    const systemIcons = Object.entries(iconMap)
      .filter(([key]) => key.toLowerCase().includes(searchTerm))
      .map(([key, value]) => ({
        key: key,
        value: value,
        name: key
      }));
    filteredIcons.value = systemIcons;
  }
};

// 选择图标
const selectIcon = (iconValue) => {
  selectedIcon.value = iconValue;
};

// 确认选择图标
const confirmIconSelection = () => {
  if (selectedIcon.value) {
    // 根据图标类型设置值
    if (iconDisplayMode.value === 'system') {
      // 系统图标存储格式:'system:emoji'
      functionForm.icon = `system:${selectedIcon.value}`;
    } else {
      // Font Awesome图标存储格式:'class:color'
      functionForm.icon = `${selectedIcon.value}:${selectedColor.value}`;
    }
    
    // 更新图标预览
    updateIconPreview();
    
    // 隐藏图标选择器
    hideIconSelector();
  }
};

// 更新图标预览
const updateIconPreview = () => {
  if (functionForm.icon) {
    const iconPreviewElement = document.querySelector('.icon-preview');
    if (iconPreviewElement) {
      if (functionForm.icon.startsWith('system:')) {
        // 系统图标
        const emoji = functionForm.icon.split(':')[1];
        iconPreviewElement.innerHTML = emoji;
        iconPreviewElement.className = 'icon-preview';
        iconPreviewElement.style.color = 'black';
      } else {
        // Font Awesome图标
        const [iconClass, color] = functionForm.icon.split(':');
        iconPreviewElement.className = `icon-preview ${iconClass}`;
        iconPreviewElement.style.color = color;
        iconPreviewElement.innerHTML = '';
      }
    }
  }
};

// 点击模态框外部关闭
window.addEventListener('click', (event) => {
  if (iconSelectorModal.value && 
      event.target === iconSelectorModal.value) {
    hideIconSelector();
  }
});

5. 总结

5.1 实现特点

  1. 模块化设计:将图标选择功能封装为独立组件,便于维护和扩展
  2. 双模式支持:同时支持Font Awesome和系统符号图标,满足不同场景需求
  3. 用户友好界面:直观的网格布局,清晰的图标预览,便捷的搜索和过滤功能
  4. 灵活的颜色定制:支持为Font Awesome图标自定义颜色,增强视觉表现力
  5. 响应式设计:适配不同屏幕尺寸,提供一致的用户体验
  6. 无缝集成:与系统功能表单深度集成,支持数据双向绑定

5.2 技术亮点

  1. 动态图标类型切换:通过Vue的条件渲染实现不同类型图标的无缝切换
  2. 高效的图标过滤:实时搜索过滤功能,提升用户选择效率
  3. 灵活的数据格式:采用特定格式存储图标信息,便于解析和渲染
  4. 事件驱动架构:基于事件驱动的交互设计,提高代码可维护性
  5. 跨浏览器兼容性:使用标准Web技术,确保在主流浏览器中的兼容性

5.3 应用场景

图标选择器主要应用于系统功能设置模块,具体场景包括:

  • 菜单功能图标配置
  • 系统功能入口图标选择
  • 控制面板功能图标设置
  • 报表和数据可视化图表图标选择
  • 通知和提醒图标配置

通过这个图标选择器,用户可以方便地为系统中的各种功能选择合适的图标,提升系统的可视化效果和用户体验。

相关推荐
Electrolux2 小时前
[wllama]纯前端实现大语言模型调用:在浏览器里跑 AI 是什么体验。以调用腾讯 HY-MT1.5 混元翻译模型为例
前端·aigc·ai编程
sanra1232 小时前
前端定位相关技巧
前端·vue
起名时在学Aiifox2 小时前
从零实现前端数据格式化工具:以船员经验数据展示为例
前端·vue.js·typescript·es6
cute_ming3 小时前
关于基于nodeMap重构DOM的最佳实践
java·javascript·重构
oMcLin3 小时前
如何在Manjaro Linux上配置并优化Caddy Web服务器,确保高并发流量下的稳定性与安全性?
linux·服务器·前端
码途潇潇3 小时前
JavaScript 中 ==、===、Object.is 以及 null、undefined、undeclared 的区别
前端·javascript
之恒君3 小时前
Node.js 模块加载 - 4 - CJS 和 ESM 互操作避坑清单
前端·node.js
放牛的小伙3 小时前
vue 表格 vxe-table 加载数据的几种方式,更新数据的用法
vue.js
be or not to be3 小时前
CSS 背景(background)系列属性
前端·css·css3
前端snow3 小时前
在手机端做个滚动效果
前端