Skip to content

Latest commit

 

History

History
692 lines (585 loc) · 15 KB

File metadata and controls

692 lines (585 loc) · 15 KB

FontSizeSwitch.vue 字体大小切换组件文档

概述

FontSizeSwitch.vue是字体大小切换组件,提供用户调节系统字体大小的功能,支持小、中、大三种字体大小选择。

文件位置: src/components/common/FontSizeSwitch.vue

组件功能

1. 字体大小切换

  • 支持三种字体大小:小、中、大
  • 实时预览字体大小变化
  • 状态持久化保存
  • 全局字体大小应用
  • 响应式字体调节

2. 组件结构

<template>
  <div class="font-size-switch">
    <el-dropdown 
      @command="handleCommand" 
      trigger="click"
      placement="bottom-end"
    >
      <div class="font-size-trigger">
        <el-icon class="font-size-icon">
          <component :is="currentIcon" />
        </el-icon>
        <span class="font-size-text">{{ currentSizeText }}</span>
        <el-icon class="dropdown-icon">
          <ArrowDown />
        </el-icon>
      </div>
      
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item 
            v-for="size in fontSizes" 
            :key="size.value"
            :command="size.value"
            :class="{ 'is-active': currentSize === size.value }"
          >
            <div class="font-size-option">
              <el-icon class="option-icon">
                <component :is="size.icon" />
              </el-icon>
              <span class="option-text" :style="{ fontSize: size.previewSize }">
                {{ size.label }}
              </span>
              <el-icon v-if="currentSize === size.value" class="check-icon">
                <Check />
              </el-icon>
            </div>
          </el-dropdown-item>
          
          <el-dropdown-item divided command="reset">
            <div class="font-size-option">
              <el-icon class="option-icon">
                <RefreshLeft />
              </el-icon>
              <span class="option-text">重置默认</span>
            </div>
          </el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
  </div>
</template>

3. 脚本逻辑

<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import { useLayoutStore } from '@/stores/layout'
import { 
  ArrowDown, 
  Check, 
  RefreshLeft,
  ZoomIn,
  Minus,
  Plus
} from '@element-plus/icons-vue'

// 状态管理
const layoutStore = useLayoutStore()

// 字体大小配置
const fontSizes = ref([
  {
    value: 'small',
    label: '小号字体',
    icon: 'Minus',
    previewSize: '12px',
    cssSize: '12px',
    description: '适合高分辨率屏幕'
  },
  {
    value: 'medium',
    label: '标准字体',
    icon: 'ZoomIn',
    previewSize: '14px',
    cssSize: '14px',
    description: '推荐使用的标准大小'
  },
  {
    value: 'large',
    label: '大号字体',
    icon: 'Plus',
    previewSize: '16px',
    cssSize: '16px',
    description: '适合视力不佳的用户'
  }
])

// 当前字体大小
const currentSize = computed(() => layoutStore.fontSize)

// 当前字体大小信息
const currentSizeInfo = computed(() => {
  return fontSizes.value.find(size => size.value === currentSize.value) || fontSizes.value[1]
})

// 当前图标
const currentIcon = computed(() => currentSizeInfo.value.icon)

// 当前大小文本
const currentSizeText = computed(() => currentSizeInfo.value.label)
</script>

字体大小管理

1. 字体大小切换

// 处理命令
const handleCommand = (command) => {
  if (command === 'reset') {
    resetFontSize()
  } else {
    setFontSize(command)
  }
}

// 设置字体大小
const setFontSize = (size) => {
  // 更新状态
  layoutStore.setFontSize(size)
  
  // 应用字体大小
  applyFontSize(size)
  
  // 显示提示
  showFontSizeNotification(size)
}

// 应用字体大小
const applyFontSize = (size) => {
  const sizeInfo = fontSizes.value.find(s => s.value === size)
  if (!sizeInfo) return
  
  // 设置CSS变量
  document.documentElement.style.setProperty('--base-font-size', sizeInfo.cssSize)
  document.documentElement.setAttribute('data-font-size', size)
  
  // 更新Element Plus组件大小
  updateElementPlusSize(size)
  
  // 触发字体大小变化事件
  window.dispatchEvent(new CustomEvent('font-size-change', {
    detail: { size, sizeInfo }
  }))
}

// 更新Element Plus组件大小
const updateElementPlusSize = (size) => {
  const sizeMap = {
    small: 'small',
    medium: 'default',
    large: 'large'
  }
  
  const elSize = sizeMap[size] || 'default'
  
  // 更新全局配置
  if (window.$ELEMENT) {
    window.$ELEMENT.size = elSize
  }
  
  // 更新CSS类
  document.documentElement.className = document.documentElement.className
    .replace(/el-size-\w+/g, '')
  document.documentElement.classList.add(`el-size-${elSize}`)
}

// 重置字体大小
const resetFontSize = () => {
  setFontSize('medium')
}

// 显示字体大小通知
const showFontSizeNotification = (size) => {
  const sizeInfo = fontSizes.value.find(s => s.value === size)
  if (!sizeInfo) return
  
  ElMessage({
    message: `字体大小已切换为:${sizeInfo.label}`,
    type: 'success',
    duration: 2000,
    showClose: false
  })
}

2. 快捷键支持

// 快捷键处理
const handleKeyboard = (event) => {
  // Ctrl + 加号:增大字体
  if (event.ctrlKey && event.key === '=') {
    event.preventDefault()
    increaseFontSize()
  }
  
  // Ctrl + 减号:减小字体
  if (event.ctrlKey && event.key === '-') {
    event.preventDefault()
    decreaseFontSize()
  }
  
  // Ctrl + 0:重置字体
  if (event.ctrlKey && event.key === '0') {
    event.preventDefault()
    resetFontSize()
  }
}

// 增大字体
const increaseFontSize = () => {
  const sizes = ['small', 'medium', 'large']
  const currentIndex = sizes.indexOf(currentSize.value)
  const nextIndex = Math.min(currentIndex + 1, sizes.length - 1)
  
  if (nextIndex !== currentIndex) {
    setFontSize(sizes[nextIndex])
  } else {
    ElMessage.warning('字体大小已达到最大值')
  }
}

// 减小字体
const decreaseFontSize = () => {
  const sizes = ['small', 'medium', 'large']
  const currentIndex = sizes.indexOf(currentSize.value)
  const prevIndex = Math.max(currentIndex - 1, 0)
  
  if (prevIndex !== currentIndex) {
    setFontSize(sizes[prevIndex])
  } else {
    ElMessage.warning('字体大小已达到最小值')
  }
}

// 绑定键盘事件
onMounted(() => {
  document.addEventListener('keydown', handleKeyboard)
})

// 清理键盘事件
onUnmounted(() => {
  document.removeEventListener('keydown', handleKeyboard)
})

3. 字体大小预设

// 字体大小预设配置
const fontSizePresets = {
  small: {
    base: '12px',
    h1: '20px',
    h2: '18px',
    h3: '16px',
    h4: '14px',
    h5: '12px',
    h6: '11px',
    button: '12px',
    input: '12px',
    table: '11px'
  },
  medium: {
    base: '14px',
    h1: '24px',
    h2: '20px',
    h3: '18px',
    h4: '16px',
    h5: '14px',
    h6: '13px',
    button: '14px',
    input: '14px',
    table: '13px'
  },
  large: {
    base: '16px',
    h1: '28px',
    h2: '24px',
    h3: '20px',
    h4: '18px',
    h5: '16px',
    h6: '15px',
    button: '16px',
    input: '16px',
    table: '15px'
  }
}

// 应用字体大小预设
const applyFontSizePreset = (size) => {
  const preset = fontSizePresets[size]
  if (!preset) return
  
  // 应用各种元素的字体大小
  Object.keys(preset).forEach(key => {
    document.documentElement.style.setProperty(`--font-size-${key}`, preset[key])
  })
}

4. 响应式字体调节

// 响应式字体调节
const adjustFontSizeForDevice = () => {
  const device = layoutStore.device
  const screenWidth = window.innerWidth
  
  // 根据设备类型调整字体大小
  let adjustedSize = currentSize.value
  
  if (device === 'mobile') {
    // 移动端字体稍大一些
    if (currentSize.value === 'small') {
      adjustedSize = 'medium'
    }
  } else if (device === 'tablet') {
    // 平板端保持原有大小
    adjustedSize = currentSize.value
  } else {
    // 桌面端根据屏幕宽度调整
    if (screenWidth > 1920) {
      // 高分辨率屏幕,字体可以稍大
      if (currentSize.value === 'small') {
        adjustedSize = 'medium'
      } else if (currentSize.value === 'medium') {
        adjustedSize = 'large'
      }
    }
  }
  
  // 应用调整后的字体大小
  if (adjustedSize !== currentSize.value) {
    applyFontSize(adjustedSize)
  }
}

// 监听设备变化
watch(
  () => layoutStore.device,
  () => {
    adjustFontSizeForDevice()
  }
)

5. 字体大小动画

// 字体大小切换动画
const animateFontSizeChange = (fromSize, toSize) => {
  const duration = 300
  const startTime = Date.now()
  
  const fromInfo = fontSizes.value.find(s => s.value === fromSize)
  const toInfo = fontSizes.value.find(s => s.value === toSize)
  
  if (!fromInfo || !toInfo) return
  
  const fromPx = parseInt(fromInfo.cssSize)
  const toPx = parseInt(toInfo.cssSize)
  
  const animate = () => {
    const elapsed = Date.now() - startTime
    const progress = Math.min(elapsed / duration, 1)
    
    // 使用缓动函数
    const easeProgress = easeInOutCubic(progress)
    
    // 计算当前字体大小
    const currentPx = fromPx + (toPx - fromPx) * easeProgress
    
    // 应用字体大小
    document.documentElement.style.setProperty('--base-font-size', `${currentPx}px`)
    
    if (progress < 1) {
      requestAnimationFrame(animate)
    }
  }
  
  animate()
}

// 缓动函数
const easeInOutCubic = (t) => {
  return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
}

样式定义

1. 组件样式

.font-size-switch {
  display: inline-block;
}

.font-size-trigger {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
  user-select: none;
  
  &:hover {
    background: var(--el-fill-color-light);
  }
}

.font-size-icon {
  margin-right: 6px;
  font-size: 16px;
  color: var(--el-text-color-regular);
}

.font-size-text {
  font-size: 13px;
  color: var(--el-text-color-regular);
  margin-right: 4px;
}

.dropdown-icon {
  font-size: 12px;
  color: var(--el-text-color-placeholder);
  transition: transform 0.2s ease;
}

.font-size-trigger:hover .dropdown-icon {
  transform: rotate(180deg);
}

2. 下拉菜单样式

.font-size-option {
  display: flex;
  align-items: center;
  width: 100%;
  
  .option-icon {
    margin-right: 8px;
    font-size: 14px;
    color: var(--el-text-color-regular);
  }
  
  .option-text {
    flex: 1;
    transition: font-size 0.2s ease;
  }
  
  .check-icon {
    margin-left: 8px;
    font-size: 14px;
    color: var(--el-color-primary);
  }
}

.el-dropdown-menu__item.is-active {
  background: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
  
  .option-icon {
    color: var(--el-color-primary);
  }
}

3. 全局字体大小样式

/* 字体大小CSS变量 */
:root {
  --font-size-base: 14px;
  --font-size-h1: 24px;
  --font-size-h2: 20px;
  --font-size-h3: 18px;
  --font-size-h4: 16px;
  --font-size-h5: 14px;
  --font-size-h6: 13px;
  --font-size-button: 14px;
  --font-size-input: 14px;
  --font-size-table: 13px;
}

/* 小号字体 */
[data-font-size="small"] {
  --font-size-base: 12px;
  --font-size-h1: 20px;
  --font-size-h2: 18px;
  --font-size-h3: 16px;
  --font-size-h4: 14px;
  --font-size-h5: 12px;
  --font-size-h6: 11px;
  --font-size-button: 12px;
  --font-size-input: 12px;
  --font-size-table: 11px;
}

/* 大号字体 */
[data-font-size="large"] {
  --font-size-base: 16px;
  --font-size-h1: 28px;
  --font-size-h2: 24px;
  --font-size-h3: 20px;
  --font-size-h4: 18px;
  --font-size-h5: 16px;
  --font-size-h6: 15px;
  --font-size-button: 16px;
  --font-size-input: 16px;
  --font-size-table: 15px;
}

/* 应用字体大小 */
body {
  font-size: var(--font-size-base);
}

h1 { font-size: var(--font-size-h1); }
h2 { font-size: var(--font-size-h2); }
h3 { font-size: var(--font-size-h3); }
h4 { font-size: var(--font-size-h4); }
h5 { font-size: var(--font-size-h5); }
h6 { font-size: var(--font-size-h6); }

.el-button {
  font-size: var(--font-size-button);
}

.el-input__inner {
  font-size: var(--font-size-input);
}

.el-table {
  font-size: var(--font-size-table);
}

生命周期

1. 组件挂载

onMounted(() => {
  // 应用当前字体大小
  applyFontSize(currentSize.value)
  
  // 绑定键盘事件
  document.addEventListener('keydown', handleKeyboard)
  
  // 监听字体大小变化事件
  window.addEventListener('font-size-change', handleFontSizeChange)
})

// 处理字体大小变化事件
const handleFontSizeChange = (event) => {
  const { size, sizeInfo } = event.detail
  
  // 更新相关组件
  updateRelatedComponents(size, sizeInfo)
}

// 更新相关组件
const updateRelatedComponents = (size, sizeInfo) => {
  // 通知图表组件重新渲染
  window.dispatchEvent(new Event('resize'))
  
  // 更新表格列宽
  const tables = document.querySelectorAll('.el-table')
  tables.forEach(table => {
    if (table.__vue__) {
      table.__vue__.doLayout()
    }
  })
}

2. 组件卸载

onUnmounted(() => {
  // 移除键盘事件监听
  document.removeEventListener('keydown', handleKeyboard)
  
  // 移除字体大小变化事件监听
  window.removeEventListener('font-size-change', handleFontSizeChange)
})

使用示例

1. 基本使用

<template>
  <div class="header-tools">
    <FontSizeSwitch />
  </div>
</template>

<script setup>
import FontSizeSwitch from '@/components/common/FontSizeSwitch.vue'
</script>

2. 自定义配置

<script setup>
import { ref } from 'vue'

// 自定义字体大小配置
const customFontSizes = ref([
  { value: 'xs', label: '超小', cssSize: '10px' },
  { value: 'small', label: '', cssSize: '12px' },
  { value: 'medium', label: '', cssSize: '14px' },
  { value: 'large', label: '', cssSize: '16px' },
  { value: 'xl', label: '超大', cssSize: '18px' }
])
</script>

3. 监听字体大小变化

<script setup>
import { watch } from 'vue'
import { useLayoutStore } from '@/stores/layout'

const layoutStore = useLayoutStore()

// 监听字体大小变化
watch(
  () => layoutStore.fontSize,
  (newSize, oldSize) => {
    console.log(`字体大小从 ${oldSize} 切换到 ${newSize}`)
    
    // 执行相关操作
    handleFontSizeChange(newSize, oldSize)
  }
)

const handleFontSizeChange = (newSize, oldSize) => {
  // 重新计算布局
  nextTick(() => {
    // 触发窗口resize事件
    window.dispatchEvent(new Event('resize'))
  })
}
</script>

注意事项

  1. 性能: 字体大小切换时避免频繁的DOM操作
  2. 兼容性: 确保在不同浏览器中的字体渲染一致
  3. 可访问性: 提供键盘快捷键支持
  4. 用户体验: 提供平滑的切换动画
  5. 响应式: 在不同设备上合理调整字体大小

相关文档


最后更新时间:2025-09-19