el-alert

6 阅读1分钟
<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>