消息组件:使用缩放控制图标大小
本节目标
- 理解
font-size调节徽章大小的局限性 - 使用
transform: scale()+translateX()实现徽章的缩放 - 掌握
scale与translateX之间的线性映射关系
1. font-size 的局限
当 font-size 减小到一定程度(如 8px 以下),徽章区域的尺寸不再跟随字号继续缩小。此时需要借助 CSS transform: scale() 对整个徽章进行等比缩放:
/* font-size 已经无法再小时 */
:deep(.el-badge__content) {
transform: scale(0.5); /* 整体缩小到 50% */
}
css
但缩放后,徽章的位置会产生偏移,需要同步调整 translateX。
2. scale 与 translateX 的对应关系
通过浏览器调试观察,可以得出大致的线性映射:
| scale | translateX |
|---|---|
| 1.0 | 100% |
| 0.7 | ~85% |
| 0.5 | ~80% |
| 0.4 | ~75% |
范围约束:
scale最小值:0.4(再小则徽章肉眼不可见)scale最大值:1.0translateX最小值:75%translateX最大值:100%
计算函数实现
/**
* 根据 scale 值计算对应的 translateX
* scale 范围: 0.4 ~ 1.0
* translateX 范围: 75% ~ 100%
*/
function calculateTransform(scale: number): {
translateX: number
scale: number
} {
const minScale = 0.4
const maxScale = 1.0
const minTranslateX = 75
const maxTranslateX = 100
// 线性插值
const clampedScale = Math.min(Math.max(scale, minScale), maxScale)
const ratio = (clampedScale - minScale) / (maxScale - minScale)
const translateX = minTranslateX + ratio * (maxTranslateX - minTranslateX)
return {
translateX,
scale: clampedScale,
}
}
ts
3. 扩展 Notification 组件 Props
在原有 Props 基础上增加 scale 属性:
// components/notice/types.d.ts
import type { BadgeProps } from 'element-plus'
export interface NotificationProps extends Partial<BadgeProps> {
/** 右侧徽章图标 */
icon?: string
/** 徽章背景颜色 */
color?: string
/** 徽章字号(px) */
size?: number
/** 左侧图标颜色 */
iconColor?: string
/** 左侧图标大小 */
iconSize?: number
/** 徽章缩放比例 0.4~1.0 */
scale?: number
}
ts
4. 完整 Notification 组件实现
<!-- components/notice/Notification.vue -->
<template>
<el-badge
v-bind="$attrs"
:style="{
'--notice-bg-color': bgColor || 'var(--el-color-danger)',
'--notice-font-size': fontSize ? `${fontSize}px` : undefined,
'--notice-translate-x': `${transformData?.translateX}%`,
'--notice-scale': transformData?.scale,
}"
>
<Icon
:icon="icon"
:style="{
color: iconColor || undefined,
fontSize: iconSize ? `${iconSize}px` : undefined,
}"
/>
</el-badge>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { NotificationProps } from './types'
import Icon from '~/components/icon/IconDefine.vue'
const props = withDefaults(defineProps<NotificationProps>(), {
icon: 'ep:bell',
size: 12,
scale: 1,
})
/**
* 根据 scale 计算对应的 translateX 值
*/
function calculateTransform(scale: number): {
translateX: number
scale: number
} {
const minScale = 0.4
const maxScale = 1.0
const minTranslateX = 75
const maxTranslateX = 100
const clampedScale = Math.min(Math.max(scale, minScale), maxScale)
const ratio = (clampedScale - minScale) / (maxScale - minScale)
const translateX = minTranslateX + ratio * (maxTranslateX - minTranslateX)
return { translateX, scale: clampedScale }
}
// 使用 computed 缓存计算结果,当 scale 变化时自动更新
const transformData = computed(() => calculateTransform(props.scale))
// 颜色计算(避免与 props.color 冲突,使用别名)
const bgColor = computed(() => props.color)
const fontSize = computed(() => props.size)
</script>
<style scoped>
:deep(.el-badge__content) {
background-color: var(--notice-bg-color);
font-size: var(--notice-font-size);
transform: translateX(var(--notice-translate-x, 100%)) scale(var(--notice-scale, 1));
}
</style>
vue
5. 测试页面:动态切换 Scale
<!-- pages/component/notice/NoticeMessage.vue -->
<template>
<div class="p-4">
<h2>通知组件 - Scale 测试</h2>
<!-- 显示当前 scale 值 -->
<p>当前 scale: {{ scale }}</p>
<!-- Scale 切换按钮 -->
<div class="mb-4 flex gap-2">
<el-button @click="scale = 0.5">Scale 0.5</el-button>
<el-button @click="scale = 1.0">Scale 1.0</el-button>
<el-button @click="scale = 1.5">Scale 1.5</el-button>
</div>
<!-- 通知组件 -->
<Notification
:value="12"
:max="999"
icon="ep:bell"
color="#ff6600"
:size="12"
:scale="scale"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Notification from '~/components/notice/Notification.vue'
const scale = ref(0.5)
</script>
vue
运行效果
- 点击
Scale 0.5:徽章缩小至 50%,translateX自动调整为约 80% - 点击
Scale 1.0:徽章恢复正常大小,translateX恢复为 100% - 切换过程完全响应式,CSS 变量实时更新
6. 两种方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| font-size + background-color | 直观,精确控制字号和颜色 | 字号过小时无法继续缩小 |
| transform scale | 可以任意缩放整个徽章区域 | 需要同步调整 translateX,有线性映射关系 |
推荐:两者结合使用。先通过 font-size 和 color 控制基本样式,当需要更精细的缩放时再叠加 scale。
7. 关键知识点总结
| 知识点 | 说明 |
|---|---|
transform: scale() | CSS 缩放变换,保持元素比例 |
transform: translateX() | 水平偏移,配合 scale 使用保持位置正确 |
| 线性插值算法 | 在两个已知端点间按比例取值 |
computed() | 缓存计算结果,仅在依赖变化时重新计算 |
| CSS 变量 | 通过 --var-name 传递 JS 计算结果到 CSS |
8. 下一节预告
下一节将实现消息组件的弹出列表层:使用 ElTabs + ElDropdown 组合实现带标签页的消息弹出面板。
↑