消息组件:扩展基础组件 Badge 自定义属性
本节目标
- 在 Element Plus 的
ElBadge基础上封装通知(Notification)组件 - 扩展 Props:自定义颜色、字号、图标等属性
- 掌握通过 CSS 变量将 Props 值传入深层样式的两种思路
1. 项目结构准备
首先在项目中创建相关文件:
src/
├── components/
│ └── notice/
│ ├── Notification.vue # 基础通知组件(扩展 Badge)
│ ├── NoticeMessageList.vue # 消息列表弹出层
│ ├── Notice.vue # 业务组合组件
│ └── types.d.ts # 类型定义
├── pages/
│ └── component/
│ └── notice/
│ └── NoticeMessage.vue # 演示页面
└── components/
└── icon/
└── IconDefine.vue # 动态图标组件
text
创建演示页面 NoticeMessage.vue:
<!-- pages/component/notice/NoticeMessage.vue -->
<template>
<div class="p-4">
<h2>通知组件示例</h2>
<Notification
:value="12"
:max="9999"
icon="ep:bell"
/>
</div>
</template>
<script setup lang="ts">
import Notification from '~/components/notice/Notification.vue'
</script>
vue
2. 创建 Notification 基础组件
2.1 基础模板结构
将 ElBadge 与自定义图标组件组合:
<!-- components/notice/Notification.vue -->
<template>
<el-badge
v-bind="$attrs"
:style="{
'--notice-bg-color': color || 'var(--el-color-danger)',
'--notice-font-size': size ? `${size}px` : undefined,
}"
>
<Icon
:icon="icon"
:style="{
color: iconColor || undefined,
fontSize: iconSize ? `${iconSize}px` : undefined,
}"
/>
</el-badge>
</template>
vue
2.2 定义扩展 Props 接口
通过 extends 继承 Element Plus 的 BadgeProps,并追加自定义属性:
// components/notice/types.d.ts
import type { BadgeProps } from 'element-plus'
export interface NotificationProps extends /* Partial<BadgeProps> */ BadgeProps {
/** 右侧徽章图标 */
icon?: string
/** 徽章背景颜色 */
color?: string
/** 徽章字号(px) */
size?: number
/** 左侧图标颜色 */
iconColor?: string
/** 左侧图标大小 */
iconSize?: number
}
ts
要点:
BadgeProps中有大量非必选属性(如value、max、type),如果组件的用法不强制要求这些字段传入,建议用Partial<BadgeProps>包裹,避免 TypeScript 报必选字段缺失错误。
2.3 完整组件代码
<!-- components/notice/Notification.vue -->
<template>
<el-badge
v-bind="$attrs"
:style="{
'--notice-bg-color': color || 'var(--el-color-danger)',
'--notice-font-size': size ? `${size}px` : undefined,
}"
>
<Icon
:icon="icon"
:style="{
color: iconColor || undefined,
fontSize: iconSize ? `${iconSize}px` : undefined,
}"
/>
</el-badge>
</template>
<script setup lang="ts">
import type { NotificationProps } from './types'
import Icon from '~/components/icon/IconDefine.vue'
defineProps<NotificationProps>()
</script>
<style scoped>
:deep(.el-badge__content) {
background-color: var(--notice-bg-color);
font-size: var(--notice-font-size);
}
</style>
vue
3. CSS 变量传值思路
本节的核心问题:如何把用户传入的 color / size 传到 ElBadge 内部的 .el-badge__content 样式中?
思路一:CSS 自定义属性 + style 绑定(本节采用)
Props(color / size)
→ 根元素 style 绑定 CSS 变量
→ :deep() 选择器读取该变量
text
<template>
<el-badge
:style="{
'--notice-bg-color': color || 'var(--el-color-danger)',
'--notice-font-size': size ? `${size}px` : undefined,
}"
>
...
</el-badge>
</template>
<style scoped>
:deep(.el-badge__content) {
background-color: var(--notice-bg-color);
font-size: var(--notice-font-size);
}
</style>
vue
注意点:
- CSS 变量名自定义(如
--notice-bg-color),注意不要与 Element Plus 内部变量冲突。 - 一定要设置默认值(如
var(--el-color-danger)),否则用户不传color时徽章无背景色。 size是number类型,拼接时需要加上px单位。
思路二:CSS transform scale 缩放(下一节展开)
:deep(.el-badge__content) {
transform: scale(0.8);
}
css
当字号已经不能再小时,可以用 scale 整体缩放徽章区域。但缩放后 translateX 也需要同步调整,否则位置偏移。
4. 透传 ElBadge 原生 Props
为了让用户仍能使用 value、max、is-dot 等 Element Plus 原生属性,用 v-bind="$attrs" 实现透传:
<template>
<el-badge v-bind="$attrs">
<Icon :icon="icon" />
</el-badge>
</template>
vue
使用示例:
<Notification
:value="99"
:max="999"
icon="ep:bell"
color="#ff6600"
:size="14"
/>
vue
5. 关键知识点总结
| 知识点 | 说明 |
|---|---|
extends BadgeProps | 继承第三方组件 Props,避免重复定义 |
Partial<T> | 将所有属性标记为可选,适合透传场景 |
v-bind="$attrs" | 将父组件传入但未在 Props 中声明的属性透传给子组件 |
:deep() 选择器 | 在 scoped 样式中穿透到子组件内部元素 |
| CSS 自定义属性 | 通过 --var-name 定义变量,在 :deep() 中使用 |
style 绑定变量 | 在根元素 style 中动态设置 CSS 变量值 |
6. 下一节预告
下节课将介绍使用 CSS transform: scale() 的方式来控制徽章整体大小,以及 scale 与 translateX 之间的线性对应关系。
↑