一、带注释的完整源码
<template>
<!-- 使用过渡动画组件,动画名称为 el-alert-fade -->
<transition name="el-alert-fade">
<!-- 根容器,动态绑定多个类名 -->
<div
class="el-alert"
:class="[
typeClass, <!-- 根据 type 生成类型类名 (如 el-alert--success) -->
center ? 'is-center' : '', <!-- 是否居中显示 -->
'is-' + effect <!-- 效果类名 (light/dark) -->
]"
v-show="visible" <!-- 控制组件显示/隐藏 -->
role="alert" <!-- 无障碍访问,标记为警报区域 -->
>
<!-- 图标区域,根据 showIcon 控制显示 -->
<i
class="el-alert__icon"
:class="[iconClass, isBigIcon]" <!-- 动态绑定图标类名和大小 -->
v-if="showIcon"
></i>
<!-- 内容区域 -->
<div class="el-alert__content">
<!-- 标题区域,支持插槽和默认内容 -->
<span
class="el-alert__title"
:class="isBoldTitle"
v-if="title || $slots.title"
>
<slot name="title">{{ title }}</slot> <!-- 优先使用插槽,其次使用 title prop -->
</span>
<!-- 描述区域,优先使用默认插槽 -->
<p class="el-alert__description" v-if="$slots.default && !description">
<slot></slot> <!-- 默认插槽内容 (描述文字) -->
</p>
<p class="el-alert__description" v-if="description && !$slots.default">
{{ description }} <!-- 使用 description prop 作为描述 -->
</p>
<!-- 关闭按钮区域 -->
<i
class="el-alert__closebtn"
:class="{
'is-customed': closeText !== '', <!-- 自定义关闭文字时添加此类 -->
'el-icon-close': closeText === '' <!-- 默认关闭图标 -->
}"
v-show="closable" <!-- 根据 closable 控制显示 -->
@click="close()" <!-- 点击触发关闭逻辑 -->
>
{{closeText}} <!-- 自定义关闭文字 (如 "关闭") -->
</i>
</div>
</div>
</transition>
</template>
<script type="text/babel">
// 类型图标映射表 (type -> 图标类名)
const TYPE_CLASSES_MAP = {
'success': 'el-icon-success',
'warning': 'el-icon-warning',
'error': 'el-icon-error'
};
export default {
name: 'ElAlert', // 组件名称
// 组件接收的属性 (props)
props: {
title: { // 标题文字
type: String,
default: ''
},
description: { // 描述文字
type: String,
default: ''
},
type: { // 警告类型 (info/warning/success/error)
type: String,
default: 'info'
},
closable: { // 是否显示关闭按钮
type: Boolean,
default: true
},
closeText: { // 自定义关闭按钮文字
type: String,
default: ''
},
showIcon: { // 是否显示图标
type: Boolean,
default: false // 默认不显示图标 (需手动设置为 true)
},
center: { // 文字是否居中
type: Boolean,
default: false
},
effect: { // 背景效果 (light/dark)
type: String,
default: 'light',
validator: function(value) { // 有效性校验
return ['light', 'dark'].indexOf(value) !== -1;
}
}
},
// 组件内部状态
data() {
return {
visible: true // 控制组件是否可见 (默认显示)
};
},
// 方法
methods: {
close() { // 关闭组件逻辑
this.visible = false; // 隐藏组件
this.$emit('close'); // 触发 close 事件 (父组件可监听)
}
},
// 计算属性 (动态生成类名)
computed: {
// 生成类型类名 (如 el-alert--success)
typeClass() {
return `el-alert--${ this.type }`;
},
// 生成图标类名 (根据 type 映射)
iconClass() {
return TYPE_CLASSES_MAP[this.type] || 'el-icon-info'; // 默认 info 图标
},
// 是否需要大图标 (当有描述或默认插槽时)
isBigIcon() {
return this.description || this.$slots.default ? 'is-big' : '';
},
// 是否需要加粗标题 (当有描述或默认插槽时)
isBoldTitle() {
return this.description || this.$slots.default ? 'is-bold' : '';
}
}
};
</script>
二、学习笔记(Markdown格式)
Element UI Alert 组件深度解析
一、核心设计思想
Alert 组件通过 动态类名 + 条件渲染 实现高度可定制化,核心关注点:
- 类型驱动:通过
type属性控制主题色和图标 - 内容优先级:插槽 >
title/description属性 - 状态管理:
visible控制显示/隐藏,close事件提供交互能力
二、关键部分分析
1. 动态类名系统(重点!)
:class="[
typeClass, // 类型类名 (el-alert--success)
center ? 'is-center' : '',
'is-' + effect // 效果类名 (is-light/is-dark)
]"
typeClass:根据type生成主题类(info→el-alert--info)effect:控制背景色(light浅色/dark深色)center:文本居中样式
💡 为什么重要:这是 Element UI 组件库统一的样式设计模式,通过类名组合实现样式复用
2. 内容渲染逻辑(重点!)
<span v-if="title || $slots.title">
<slot name="title">{{ title }}</slot>
</span>
<p v-if="$slots.default && !description">
<slot></slot>
</p>
<p v-if="description && !$slots.default">
{{ description }}
</p>
- 标题优先级:插槽 >
title属性 - 描述优先级:默认插槽 >
description属性
💡 设计精髓:支持灵活的内容结构,同时保持 API 简洁
3. 关闭按钮的智能处理(重点!)
<i
:class="{
'is-customed': closeText !== '',
'el-icon-close': closeText === ''
}"
>
{{closeText}}
</i>
- 当
closeText为空 → 显示默认el-icon-close图标 - 当
closeText有值 → 显示自定义文字(如 "关闭")
💡 用户体验细节:避免在
closeText为空时显示空字符串
4. 计算属性关键逻辑
| 计算属性 | 作用 | 触发条件 |
|---|---|---|
typeClass | 生成主题类名 | type 变化 |
iconClass | 生成图标类名 | type 变化 |
isBigIcon | 控制图标大小 | 有描述/默认插槽时 |
isBoldTitle | 控制标题粗细 | 有描述/默认插槽时 |
💡 为什么用计算属性:避免在模板中写复杂逻辑,保持模板简洁
三、重点代码总结(必须掌握)
1. 动态类名生成(核心)
// 生成类型类名
typeClass() {
return `el-alert--${ this.type }`;
}
// 生成图标类名 (安全兜底)
iconClass() {
return TYPE_CLASSES_MAP[this.type] || 'el-icon-info';
}
✅ 为什么重要:Element UI 的样式系统高度依赖这种类名生成逻辑,是理解组件样式的钥匙
2. 内容渲染优先级(易错点)
<!-- 优先使用插槽,其次使用属性 -->
<span v-if="title || $slots.title">
<slot name="title">{{ title }}</slot>
</span>
<!-- 优先使用默认插槽 -->
<p v-if="$slots.default && !description">
<slot></slot>
</p>
⚠️ 常见错误:直接使用
v-if="description"会导致描述文字被覆盖
3. 关闭按钮的智能处理(细节控)
<i
:class="{
'is-customed': closeText !== '',
'el-icon-close': closeText === ''
}"
>
{{closeText}}
</i>
✅ 设计亮点:用一个类名控制两种状态(图标/文字),避免冗余条件
四、学习建议
-
动手实践:
<!-- 尝试不同配置 --> <el-alert title="成功提示" type="success" description="这是成功描述" :closable="true" :show-icon="true" /> -
调试技巧:
- 打开浏览器开发者工具 → Elements 面板
- 修改
type/effect属性 → 观察类名变化 - 检查
el-alert--success等类在 CSS 中的定义
-
扩展思考:
- 如何添加
close事件的回调? - 如果要支持
info类型的自定义图标,如何修改? effect属性的 CSS 实现逻辑(需查看 Element UI 的 CSS 文件)
- 如何添加
💎 总结:这个组件完美体现了 "属性驱动样式" 和 "内容优先级" 的设计哲学,是学习 Element UI 样式系统的关键案例。重点掌握动态类名生成和内容渲染逻辑,能快速理解其他组件。