從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 官方文檔

相關文章
相關標籤/搜索