el-alert

11 阅读3分钟

一、带注释的完整源码

<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 组件通过 动态类名 + 条件渲染 实现高度可定制化,核心关注点:

  1. 类型驱动:通过 type 属性控制主题色和图标
  2. 内容优先级:插槽 > title/description 属性
  3. 状态管理visible 控制显示/隐藏,close 事件提供交互能力

二、关键部分分析

1. 动态类名系统(重点!)

:class="[
  typeClass,          // 类型类名 (el-alert--success)
  center ? 'is-center' : '',
  'is-' + effect      // 效果类名 (is-light/is-dark)
]"
  • typeClass:根据 type 生成主题类(infoel-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>

设计亮点:用一个类名控制两种状态(图标/文字),避免冗余条件


四、学习建议

  1. 动手实践

    <!-- 尝试不同配置 -->
    <el-alert 
      title="成功提示" 
      type="success"
      description="这是成功描述"
      :closable="true"
      :show-icon="true"
    />
    
  2. 调试技巧

    • 打开浏览器开发者工具 → Elements 面板
    • 修改 type/effect 属性 → 观察类名变化
    • 检查 el-alert--success 等类在 CSS 中的定义
  3. 扩展思考

    • 如何添加 close 事件的回调?
    • 如果要支持 info 类型的自定义图标,如何修改?
    • effect 属性的 CSS 实现逻辑(需查看 Element UI 的 CSS 文件)

💎 总结:这个组件完美体现了 "属性驱动样式""内容优先级" 的设计哲学,是学习 Element UI 样式系统的关键案例。重点掌握动态类名生成和内容渲染逻辑,能快速理解其他组件。