<template>
<!-- 使用 Vue 的 <transition> 组件实现淡入淡出动画 -->
<!-- 动画名称为 'el-alert-fade',对应 CSS 中定义的 enter/leave 类 -->
<transition name="el-alert-fade">
<!-- 根元素 div,作为 alert 的容器 -->
<!-- :class 动态绑定多个类名:类型类(如 el-alert--success)、居中类(is-center)、主题类(is-light / is-dark) -->
<!-- v-show 控制显隐,false 时隐藏但不销毁 DOM,避免实例丢失导致关闭失败 -->
<!-- role="alert" 符合 WAI-ARIA 规范,屏幕阅读器可自动播报,提升无障碍访问体验 -->
<div
class="el-alert"
:class="[typeClass, center ? 'is-center' : '', 'is-' + effect]"
v-show="visible"
role="alert"
>
<!-- 左侧状态图标,仅当 showIcon 为 true 时渲染 -->
<!-- :class 绑定图标类名(由 iconClass 计算得出)和是否大图标的修饰符(is-big) -->
<i class="el-alert__icon" :class="[iconClass, isBigIcon]" v-if="showIcon"></i>
<!-- 内容区域,包含标题、描述文本和关闭按钮 -->
<!-- 采用语义化结构组织内容,确保可读性和样式隔离 -->
<div class="el-alert__content">
<!-- 标题部分,当 title prop 或 title 插槽存在时显示 -->
<!-- :class 绑定 isBoldTitle,决定标题是否加粗显示(有描述时增强层级感) -->
<span class="el-alert__title" :class="[isBoldTitle]" v-if="title || $slots.title">
<!-- 插槽优先于 title 属性显示,支持自定义 HTML 结构 -->
<slot name="title">{{ title }}</slot>
</span>
<!-- 描述文本第一种情况:默认插槽存在且 description 为空字符串时 -->
<!-- 支持富文本内容,优先级高于 description 属性 -->
<p class="el-alert__description" v-if="$slots.default && !description">
<slot></slot>
</p>
<!-- 描述文本第二种情况:无默认插槽但 description 属性有值时 -->
<!-- 显示纯文本描述 -->
<p class="el-alert__description" v-if="description && !$slots.default">
{{ description }}
</p>
<!-- 关闭按钮,仅当 closable 为 true 时显示 -->
<!-- :class 判断是否使用自定义文本(is-customed)或默认图标(el-icon-close) -->
<!-- @click 绑定 close 方法,触发关闭逻辑并 emit 事件 -->
<i
class="el-alert__closebtn"
:class="{ 'is-customed': closeText !== '', 'el-icon-close': closeText === '' }"
v-show="closable"
@click="close()"
>{{ closeText }}</i>
</div>
</div>
</transition>
</template>
<script type="text/babel">
/**
* Element UI Alert 组件 (ElAlert)
*
* 说明:
* `el-alert` 是一个轻量级提示组件,用于展示成功、警告、错误、信息等反馈。
* 它不会自动消失,必须通过用户点击关闭按钮或外部逻辑控制显隐。
*
* 特性:
* - 支持多种类型(success/warning/info/error)
* - 可切换主题(light/dark)
* - 支持图标、文字居中、自定义关闭文本
* - 提供插槽来自定义标题与内容
* - 符合 WAI-ARIA 无障碍规范
*
* 注意事项:
* - 推荐使用 `v-show` 而非 `v-if` 控制显隐,防止实例销毁后调用 close 失败
* - 若需自动关闭,请确保停留时间足够长(建议 ≥10 秒),以免信息被忽略
* - 频繁弹出会影响用户体验,尤其对认知障碍用户不友好,应合理控制触发频率
* - Vue 3 项目推荐迁移至 Element Plus,API 高度兼容
*/
// 定义不同类型对应的图标类名映射表
const TYPE_CLASSES_MAP = {
'success': 'el-icon-success', // 成功提示:绿色对勾
'warning': 'el-icon-warning', // 警告提示:黄色感叹号
'error': 'el-icon-error' // 错误提示:红色叉号
// info 类型未在此定义,计算属性中会回退到 el-icon-info
};
export default {
name: 'ElAlert', // 组件名称,用于调试、递归引用及 devtools 识别
// 接收外部传入的配置属性
props: {
title: {
type: String,
default: '' // 主标题文本,默认为空
},
description: {
type: String,
default: '' // 辅助性描述文本,默认为空
},
type: {
type: String,
default: 'info', // 提示类型,决定颜色方案和默认图标
// 可选值:success / warning / info / error
},
closable: {
type: Boolean,
default: true // 是否显示关闭按钮,默认可关闭
},
closeText: {
type: String,
default: '' // 自定义关闭按钮文本;若为空,则显示 × 图标
},
showIcon: {
type: Boolean,
default: false // 是否显示左侧状态图标
},
center: {
type: Boolean,
default: false // 文字内容是否水平居中对齐
},
effect: {
type: String,
default: 'light', // 主题风格
validator: function(value) {
return ['light', 'dark'].indexOf(value) !== -1; // 仅允许 'light' 或 'dark'
}
}
},
// 响应式数据,控制组件自身状态
data() {
return {
visible: true // 控制组件是否可见,初始为 true;关闭后设为 false
};
},
// 方法定义:处理交互逻辑
methods: {
/**
* 关闭方法
* - 将 visible 设为 false,触发 v-show 隐藏和 transition 动画
* - 向父组件 emit 'close' 事件,供其执行后续逻辑(如埋点、重置状态等)
*/
close() {
this.visible = false;
this.$emit('close'); // 触发 close 事件,无参数传递
}
},
// 计算属性:基于 props 和响应式数据动态生成结果
computed: {
/**
* 根据 type 属性生成对应的修饰符类名
* 如:type="success" → 返回 "el-alert--success"
* 该类名用于应用不同颜色主题(绿/黄/蓝/红背景)
*/
typeClass() {
return `el-alert--${this.type}`;
},
/**
* 根据 type 查找对应的状态图标类名
* 若命中 success/warning/error,则返回对应图标类
* 否则回退到 el-icon-info(适用于 info 类型)
*/
iconClass() {
return TYPE_CLASSES_MAP[this.type] || 'el-icon-info';
},
/**
* 判断是否应显示大尺寸图标
* 当存在描述内容(description 不为空 或 默认插槽有内容)时返回 'is-big'
* 使图标视觉上更协调
*/
isBigIcon() {
return this.description || this.$slots.default ? 'is-big' : '';
},
/**
* 判断标题是否应加粗显示
* 当存在描述内容时启用 'is-bold' 类,增强内容层级
*/
isBoldTitle() {
return this.description || this.$slots.default ? 'is-bold' : '';
}
}
};
</script>
<style scoped>
/* 本组件样式已由 Element UI 全局主题提供,此处无需重复定义 */
/* 实际项目中请确保引入 element-ui/lib/theme-chalk/index.css */
</style>