Element源码分析系列3-Button(按钮)

栏目: 编程工具 · 发布时间: 6年前

内容简介:Button(按钮)可能是最简单的一个组件了(Icon组件表示不服,我TM连点击事件都没),因为Button涉及到的东西真的不多,无非就是响应点击事件和具体的样式编写,最多加一个loading状态禁止点击,下图是Element的Button示意图,官网代码主要就分为直角,圆角,圆形按钮这几种,这里的按钮颜色看着很舒服,比如危险按钮的颜色不是#ff0000,而是有一点淡的红色,视觉效果更柔和,可以借鉴这些颜色直接上代码,代码量不多

Button(按钮)可能是最简单的一个组件了(Icon组件表示不服,我TM连点击事件都没),因为Button涉及到的东西真的不多,无非就是响应点击事件和具体的样式编写,最多加一个loading状态禁止点击,下图是Element的Button示意图,官网代码 点此

Element源码分析系列3-Button(按钮)

主要就分为直角,圆角,圆形按钮这几种,这里的按钮颜色看着很舒服,比如危险按钮的颜色不是#ff0000,而是有一点淡的红色,视觉效果更柔和,可以借鉴这些颜色

Button源码分析

直接上代码,代码量不多

<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>
<script>
  export default {
    name: 'ElButton',
    inject: {
      elForm: {
        default: ''
      },
      elFormItem: {
        default: ''
      }
    },
    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
    },
    computed: {
      _elFormItemSize() {
        return (this.elFormItem || {}).elFormItemSize;
      },
      buttonSize() {
        return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
      },
      buttonDisabled() {
        return this.disabled || (this.elForm || {}).disabled;
      }
    },
    methods: {
      handleClick(evt) {
        this.$emit('click', evt);
      }
    }
  };
</script>
复制代码

我们一步步分析,首先很明确, <el-button> 就是封装了原生的button而已,原生button有个地方需要注意,请始终为 <button> 元素规定 type 属性。不同的浏览器对 <button> 元素的 type 属性使用不同的默认值,值有3种, button , submit , reset 分别表示按钮,提交,重置。而且如果在 HTML 表单中使用 <button> 元素,不同的浏览器可能会提交不同的按钮值。请使用 <input> 在 HTML 表单中创建按钮

首先我们来看第一句 class="el-button" ,这里声明了按钮的基本类,也就是所有按钮通用的样式,见下图

Element源码分析系列3-Button(按钮)

可以看到其中有几个样式比较重要,首先是 display:inline-block ,表明按钮内联块状分布,一行可以有多个排列,且可以控制宽高, -webkit-appearence:none 表示将按钮原生的样式去掉,首先是太丑其实不同浏览器表现不同,注意这里的按钮没有设置宽高,宽高都是由字体大小撑开来的,然后设置 padding 来产生内间距, line-height:1 表示行高和字体大小一样

然后第二句 @click="handleClick" 这个是重点,这表明给原生button绑定了点击事件,我们使用该组件时是按下图的方式

Element源码分析系列3-Button(按钮)
这里需要手动写一个 @click ,然后我们看一下 handleClick

的代码

methods: {
      handleClick(evt) {
        this.$emit('click', evt);
      }
}
复制代码

这里实际上是用Vue的内置事件系统向父级触发了一个click事件,父级就是 <el-button> ,因为实际点击我们是点击在原生button上的,而使用组件时却是在 <el-button> 上监听事件,所以这里需要将click事件派发到父级,父级监听这个click事件,第二个参数是事件对象。如果不写这个 handleClick 将不会触发任何点击效果

第三句 :disabled="buttonDisabled || loading" 表示控制按钮的禁用状态,注意disabled是原生的属性,当其为true时,按钮无法被点击,且鼠标hover的样式不是小手,这里禁用状态是由loading状态和用户自定义的禁用与否共同决定,其中用户定义的disabled会被转化为一个计算属性,如下,后面的项表示表单相关的内容,此处不详细解释

禁用状态是由2部分组成:一是功能禁用,通过原生的disabled属性来实现,二是样式上禁用,通过将按钮置灰和 cursor:not-alowed 将鼠标展示为一个禁止的标志来实现

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

再来看 :autofocus="autofocus" 这句话,如果为true表示按钮自动获得焦点,按钮获得焦点就是按钮为focus的状态,可以用于提示用户

:type="nativeType" 表示按钮的原生类型,button ,reset还是submit,接下来是控制按钮不同种类的class

:class="[
      type ? 'el-button--' + type : '',
      buttonSize ? 'el-button--' + buttonSize : '',
      {
        'is-disabled': buttonDisabled,
        'is-loading': loading,
        'is-plain': plain,
        'is-round': round,
        'is-circle': circle
      }
    ]"
复制代码

这里注意绑定的class是一个数组,里面又混合了对象的形式,这种写法可以借鉴,对象里面的类控制了该按钮是否是禁用,loading,朴素,圆角,圆形,然后是这3句话

<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>
复制代码

这3句就是 <button></button> 中间的内容了,第一个i标签表示加载状态下的loading图案,可以看出这个图案就是一个字体图标而已,在不断的旋转( animation:rotating 2s linear infinite )

Element源码分析系列3-Button(按钮)
Element源码分析系列3-Button(按钮)

第二个i标签是按钮的图标,用户设置,此图标在loading状态下隐藏,然后是 <span> 这个标签当且仅当 <el-button> 中有内容时才存在,内容放在slot插槽中, $slots.default 来判断是否有子元素存在,可以借鉴

后面的 inject 估计是和表单相关,这里不做介绍,注意一下当按钮被点击时,样式也会发生变化,下图中成功按钮被点击变成深色,这是通过css的 :active 伪类来实现,我之前一直以为只有a标签有active伪类,原来button也可以用啊

Element源码分析系列3-Button(按钮)

下面讲讲按钮的大小控制,其实很简单,

Element源码分析系列3-Button(按钮)
size属性在通过绑定class的这句话 buttonSize ? 'el-button--' + buttonSize : '' 将size转化为类名,从而使用不同的尺寸类来控制大小, buttonSize

是个计算属性通过size得到

综上,我们明白了组件的各种属性最终会转化为对应的class来控制按钮的样式表现,就是在:class里拼接字符串而已

ButtonGroup源码分析

ButtonGroup就是按钮组,将多个按钮组合在一起,如下图

Element源码分析系列3-Button(按钮)
其源码就更简单了,就是封装了一个div,注意 el-button-group 的内容是 display:inline-block

,也就说明这个wrapper其实也是内联块状的表现,里面的slot承载子button

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

这里重点在按钮之间的白色间隙是怎么实现的,答案就是css伪类 :last-child:first-child:not:first-child 选择器用于选取 属于其父元素的首个子元素的指定选择器 ,也就是说如果多个相同层级的p标签排在一起,他们的父元素是div,那么p:first-child就会选中第一个p标签

下面上scss代码

@each $type in (primary, success, warning, danger, info) {
    .el-button--#{$type} {
      &:first-child {
        border-right-color: rgba($--color-white, 0.5);
      }
      &:last-child {
        border-left-color: rgba($--color-white, 0.5);
      }
      &:not(:first-child):not(:last-child) {
        border-left-color: rgba($--color-white, 0.5);
        border-right-color: rgba($--color-white, 0.5);
      }
    }
  }
复制代码

很明显,这里设置了第一个元素的右侧border和最后一个的左侧border,对于既不是第一个也不是最后一个的元素,设置双侧border,注意这里只设置了border的颜色,其实所有按钮默认都有border,颜色和按钮主体颜色一致,所以这里只修改了颜色就能达到目的


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Practical Django Projects, Second Edition

Practical Django Projects, Second Edition

James Bennett / Apress / 2009 / 44.99

Build a django content management system, blog, and social networking site with James Bennett as he introduces version 1.1 of the popular Django framework. You’ll work through the development of ea......一起来看看 《Practical Django Projects, Second Edition》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具