阅读 408
Element 2 组件源码剖析之Button按钮

Element 2 组件源码剖析之Button按钮

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

0x00 简介

组件 Button 标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。 本文将深入分析源码,剖析其实现原理,耐心读完,相信会对您有所帮助。源码实现详见packages/button/src/ 文件夹下  button.vue、 button-group.vue 等组件实现。 🔗 组件文档 Breadcrumb 🔗 gitee源码

更多组件剖析详见 👉 📚 Element 2 源码剖析组件总览


按钮组件有两部分 <button><button-group>,组件源码都在 packages/button/src/ 文件夹下。在项目工程化机制下,每个组件对应各自的文件夹 component-name, 定义导出组件并为其扩展 install 方法,以 commonjs2 规范对每个组件单独打包构建,支持按需引入。

0x01 button-group 按钮组

button-group.vue 组件是包裹button按钮的容器。 组件创建一个 class 名为el-button-group<div>元素容器,提供了匿名插槽,用于分发button组件使用内容。

<template>
  <div class="el-button-group">
    <slot></slot>
  </div>
</template>
<script>
  export default {
    name: 'ElButtonGroup'
  };
</script>
复制代码

0x02 button 组件

template 模板内容

组件创建一个class 名为el-button的原生button元素,内部由loading 加载图标icon 图标以及自定义按钮文本等三部分组成。

<template>
  <button
    class="el-button"
    @click="handleClick"
    :disabled="buttonDisabled || loading"
    :autofocus="autofocus"
    :type="nativeType"
    :class="[
      type ? 'el-button--' + type : '',
      buttonSize ? 'el-button--' + buttonSize : '',
      {
        'is-disabled': buttonDisabled,
        'is-loading': loading,
        'is-plain': plain,
        'is-round': round,
        'is-circle': circle
      }
    ]"
  >
    <i class="el-icon-loading" v-if="loading"></i>
    <i :class="icon" v-if="icon && !loading"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>
复制代码

button元素根节点

  • 监听click事件,绑定了handleClick回调函数。

  • 禁用状态由计算属性buttonDisabled、按钮加载状态loading属性值判定。

  • 通过 autofocus 属性值设定当页面加载时按钮是否有输入焦点。

  • 原生 button 类型设置。可选值 button / submit / reset

    • submit:  此按钮将表单数据提交给服务器。如果未指定属性,或者属性动态更改为空值或无效值,则此值为默认值。
    • reset:  此按钮重置所有组件为初始值。
    • button: 此按钮没有默认行为。它可以有与元素事件相关的客户端脚本,当事件出现时可触发。
  • 动态添加样式:

    • 根据 type 属性值添加类型样式el-button--[primary/success/warning/danger/info/text]
    • 根据计算属性buttonSize 添加尺寸样式 el-button--[medium/small/mini]
    • 根据计算属性buttonDisabled和prop的 loadingplainroundcircle等属性,设置 is-disabled按钮禁用状态、 is-loading按钮加载状态、 is-plain朴素按钮、 is-round圆角按钮、 is-circle圆形按钮。

内部元素节点

  • loading 加载图标 :若 loading 属性值为 true,按钮为加载状态。 渲染一个使用名称 el-icon-loading 的 Icon 图标。
  • icon 图标 :若 icon属性设定了图标类名(truthy),且按钮不是加载状态,渲染该类名图标。
  • 自定义按钮文本 :提供了匿名插槽的 <span>元素,只有分发内容时才会渲染v-if="$slots.default"

通过设置 Button 的属性来产生不同的按钮样式,推荐顺序为:type -> plain -> round/circle -> size -> loading -> disabled

attributes 属性

组件 prop 定义如下:

props: {
  type: {
    type: String,
    default: 'default'
  },
  size: String,
  icon: {
    type: String,
    default: ''
  },
  nativeType: {
    type: String,
    default: 'button'
  },
  loading: Boolean,
  disabled: Boolean,
  plain: Boolean,
  autofocus: Boolean,
  round: Boolean,
  circle: Boolean
},
复制代码
参数说明类型可选值默认值
size尺寸stringmedium / small / mini
type类型stringprimary / success / warning / danger / info / text
plain是否朴素按钮booleanfalse
round是否圆角按钮booleanfalse
circle是否圆形按钮booleanfalse
loading是否加载中状态booleanfalse
disabled是否禁用状态booleanfalse
icon图标类名string
autofocus是否默认聚焦booleanfalse
native-type原生 type 属性stringbutton / submit / resetbutton

click 事件

监听组件的 click 事件 。当点击触发 click 事件,执行 handleClick(evt) 方法,调用 this.$emit('click', evt); 触发当前实例上的click事件 。

methods: {
  handleClick(evt) {
    // 触发当前实例上的事件 
    this.$emit('click', evt);
  }
}
复制代码

计算属性

buttonSize

用来获取按钮的尺寸,根据 size属性、使用Form 表单时FormItem的 计算属性 elFormItemSize,还有组测组件时全局属性设置 this.$ELEMENT.size

使用依赖注入的 inject 选项接收FormItem实例,获取其计算属性 elFormItemSize

// form-item 组件
inject: {
  elFormItem: {
    default: ''
  }
},

computed: {
  _elFormItemSize() {
    return (this.elFormItem || {}).elFormItemSize;
  },
  buttonSize() {
    return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
  },
},
复制代码

同样form-item组件中使用inject 选项接收form实例,用于计算元素尺寸 elFormItemSize,由 form-itemform各自的 size属性值计算可得 。

// packages\form\src\form-item.vue
provide() {
  return {
    elFormItem: this
  };
}, 
inject: ['elForm'],

props: { 
  size: String
}, 
computed: { 
  _formSize() {
    return this.elForm.size;
  },
  elFormItemSize() {
    return this.size || this._formSize;
  }, 
},

// packages\form\src\form.vue 
provide() {
  return {
    elForm: this
  };
},

props: { 
  size: String, 
}, 
复制代码

buttonDisabled

用来判断按钮的禁用状态,根据 disabled属性、Form 表单的disabled属性判定。

inject: {
  elForm: {
    default: ''
  },
},

computed: {
  buttonDisabled() {
    return this.disabled || (this.elForm || {}).disabled;
  }
},
复制代码

使用inject 选项接收form组件实例,获取其 prop disabled属性。

// packages\form\src\form.vue
provide() {
  return {
    elForm: this
  };
},

props: { 
  disabled: Boolean, 
},
复制代码

0x03 📚参考

"button",MDN
"依赖注入",vuejs.org

0x04 关注专栏

此文章已收录到专栏中 👇,可以直接关注。

文章分类
前端
文章标签