乐趣区

关于前端:从Element3中学习Vue30-elbutton

在阅读文章之前,我曾经默认你曾经把握了 Vue3.0 的根本应用,文章中次要剖析其中组件开发过程中的思路以及一些 Api 的解说。心愿这篇文章能帮忙你更加的理解 Element3Vue3.0的应用和组件的开发能带来一些帮忙。

Template

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

<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~

props

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

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 则标识验证通过,返回谬误即验证失败。

仔细的小伙伴或者曾经发现了,其中蕴含属性 native-type 原生属性也挂载了下来,然而这个值并没有应用 validator 进行值的校验,可能在 Element3 开发人员可能为了不便当前的拓展吧,如果原声中 native-type 增加其余的值依赖组件库的我的项目即能够间接应用,无需更改组件库局部,同时也不心愿组件库去影响原生的某些属性。

笔者也看了一下文档在 Element3Button的文档中,提供 autofocus 属性,然而在组件中却没有接管这个这个属性,咱们这个时候再次看下 HTML 局部,在 tempalte 就间接是 button 标签了,所以当咱们在 <el-button autofocus> 的时候 autofocus 就曾经被挂载下来了。

逻辑解决

介绍完参数局部之后接下来咱们持续向下看一下 setup,通过Vue3.0 的改良 setup 曾经承载了页面中大部分的逻辑,所以 el-button 也是天然。

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 转换成了绑定对象。

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 官网文档

退出移动版