从Element3中学习Vue3.0 - el-button

在阅读文章以前,我已经默认你已经掌握了Vue3.0的基本使用,文章中主要分析其中组件开发过程当中的思路以及一些Api的讲解。但愿这篇文章能帮助你更加的了解Element3Vue3.0的使用和组件的开发能带来一些帮助。javascript

Template

废话也就很少赘述了,首先在上面所说的Element3Git地址上拉取最新源码,以后在package文件夹中找到button文件夹下的Button.vue,这个组件就是介绍第一个组件<el-button/>。对于tempalte方面就很少赘述了大概内容以下:html

<template>
  <button class="el-button"
            :class="classes"
            :type="nativeType"
            :disabled="buttonDisabled || loading">
    <i class="el-icon-loading" v-if="loading"></i>
    <i :class="icon" v-else-if="icon"></i>
    <span v-if="$slots.default">
      <slot></slot>
    </span>
  </button>
</template>

上述结构中的loading就不用多说了这里也是蛮通俗的,这个地方优先展现的是loading,其次才是icon图标,在Button组件中还使用了$slots.default该值指向的是插入当前组件的默认slot,也就是常说的匿名slot。这里用了一个很巧妙的手法就是,若是匿名组件存在的下才会使用slot而不是直接吧slot挂载组件中。这就很Nice~vue

props

button动态绑定了calss、type、disabled这个地方稍后再说,先标记一下,首先看下组件的入参(即:props):java

export default {
  props: {
    //  控制按钮大小
    size: {
        type: String,
        validator(val) {
            if (val === '') return true
            return ['medium', 'small', 'mini'].indexOf(val) !== -1
        }
    },
    //  控制按钮类型
    type: {
        type: String,
            validator(val) {
            return (
                ['primary', 'success', 'warning', 'danger', 'info', 'text']
                .indexOf(val) !== -1
            )
        }
    },
    //  原生类型
    nativeType: {
        type: String,
        default: 'button'
    },
    //  是否朴素按钮
    plain: Boolean,
    //  是否圆角按钮
    round: Boolean,
    //  是否圆形circle
    circle: Boolean,
    //  是否loading
    loading: Boolean,
    //  是否禁用
    disabled: Boolean,
    //  图标类名
    icon: String
  }
};

经过上面的源码中能够看出sizetype参数使用了自定义校验器(validator),若是没有仔细阅读过Vue文档的同窗可能对validator会有些许的陌生,validator能够在方法能够更加精确的规范参数的值,如size中只能传入medium,small,minivalidator方法返回的是一个boolean值,当没有传入规定的值,则会抛出错误无效的道具。也就时说validator会根据若是返回的值为true则标识验证经过,返回错误即验证失败。git

细心的小伙伴或许已经发现了,其中包含属性native-type原生属性也挂载了上去,可是这个值并无使用validator进行值的校验,可能在Element3开发人员可能为了方便之后的拓展吧,若是原声中native-type添加其余的值依赖组件库的项目便可以直接使用,无需更改组件库部分,同时也不但愿组件库去影响原生的某些属性。github

笔者也看了一下文档在Element3Button的文档中,提供autofocus属性,可是在组件中却没有接收这个这个属性,咱们这个时候再次看下HTML部分,在tempalte就直接是button标签了,因此当咱们在<el-button autofocus>的时候autofocus就已经被挂载上去了。数组

逻辑处理

介绍完参数部分以后接下来咱们继续向下看一下setup,通过Vue3.0的改进setup已经承载了页面中大部分的逻辑,因此el-button也是天然。app

import { useGlobalOptions } from '../../src/use/globalConfig';
import { toRefs, inject, computed } from 'vue'

export default {
    setup(props) {
        const { size, disabled } = toRefs(props)
        
        const buttonSize = useButtonSize(size)
        const buttonDisabled = useButtonDisabled(disabled)
        const classes = useClasses({
            props,
            size: buttonSize,
            disabled: buttonDisabled
        })
        return {
            buttonDisabled,
            classes
        }
    }
}

因为在setup中是没有this因此setup的第一个参数便是props传入的参数属性参数,但获取到的对象是一个普通对象没法完成双向绑定,经过toRefs转换成了绑定对象。ide

buttonSize

setupclass进行了统一的处理,那么咱们就看下这部分的内容,方法中首先处理的是buttonSize,具体代码以下。学习

const useButtonSize = (size) => {
    //  获取当前组件实例
    const globalConfig = useGlobalOptions()
    return computed(() => {
        const elFormItem = inject('elFormItem', {})
        return size?.value || elFormItem.elFormItemSize || globalConfig.size
    })
}

src/use/globalConfig

export function useGlobalOptions() {
    //  获取当前组件实例
    const instance = getCurrentInstance()
    if (!instance) {
        console.ware('useGlobalOptions must be call in setup function')
        return
    }
    return instance.appContext.config.globalProperties.$ELEMENT || {}
}

useButtonSize方法中经过公用方法获取到当前组件的示例,若是当前组件的实例存在的话则经过全局属性,获取到当前组件的全局信息(组件全局信息实在初始化时手动配置的信息,名为$ELEMENT),若没有会获取到全局信息,则默认返回一个空对象。以后经过inject接收父级elFormItem传递过来的数据,并传入一个空对象做为默认值。

完成上述操做以后,在useButtonSize方法中经过计算属性,获取到size属性值,其优先级为props > elFormItem > globalConfig,最后将计算结果返回出去。

useButtonDisabled

处理完上述以后就处理了一下按钮的是否可用样式useButtonDisabled,具体代码以下:

const useButtonDisabled = (disabled) => {
    return computed(() => {
        const elForm = inject('elForm', {});
        return disabled?.value || elForm.disabled;
    });
};

其实这里的处理逻辑和处理buttonsize是差很少的,这里对代码就很少赘述了,这里一样是返回了所获取到的值。这里接收的再也不是elFormItem的值,而是elForm的值,经过这里能够得出,Element3elForm传入button会使整个表单所有都禁用。

注:关于inject所接收的值,这里就很少赘述,分析其组件时会进行讲解

useClasses

获取到全部的参数以后,则是经过useClasses方法统一处理class名称:

const useClasses = ({ props, size, disabled }) => {
  return computed(() => {
    return [
      size.value ? `el-button--${size.value}` : '',
      props.type ? `el-button--${props.type}` : '',
      {
        'is-plain': props.plain,
        'is-round': props.round,
        'is-circle': props.circle,
        'is-loading': props.loading,
        'is-disabled': disabled.value
      }
    ]
  })
}

关于class动态渲染这里,使用了计算属性,而不是一一对应绑定的,这样作的好处是能够统一维护其class的样式,还有点能够说的就是,在渲染class的时候,使用的是数组嵌套对象的形式,可能笔者比较菜,尚未用过这种方式动态渲染class,经过代码能够明确的看出useClasses方法只是简单的经过计算数据对全部相关的class名称进行了统一的处理。针不戳~

总结

上述代码已是整个el-button组件的所有,虽然是一个很简单的组件,可是却能在里面学到一些东西,好比Vue3.0Provide/Inject,总体代码思路清晰代码结构简单,都是咱们值得学习的地方。

哪有什么岁月静好,不过是有人替你负重前行。感谢为Element3默默付出的程序大佬们。

若是你们感兴趣的话就点击下方链接,Star一下吧。

Element3 Git地址
Element3 官方文档

相关文章
相关标签/搜索