在閱讀文章以前,我已經默認你已經掌握了Vue3.0
的基本使用,文章中主要分析其中組件開發過程當中的思路以及一些Api
的講解。但願這篇文章能幫助你更加的瞭解Element3
和Vue3.0
的使用和組件的開發能帶來一些幫助。javascript
Template
廢話也就很少贅述了,首先在上面所說的Element3
Git地址上拉取最新源碼,以後在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 } };
經過上面的源碼中能夠看出size
和type
參數使用了自定義校驗器(validator
),若是沒有仔細閱讀過Vue
文檔的同窗可能對validator
會有些許的陌生,validator
能夠在方法能夠更加精確的規範參數的值,如size
中只能傳入medium,small,mini
。validator
方法返回的是一個boolean
值,當沒有傳入規定的值,則會拋出錯誤無效的道具
。也就時說validator
會根據若是返回的值爲true
則標識驗證經過,返回錯誤即驗證失敗。git
細心的小夥伴或許已經發現了,其中包含屬性native-type
原生屬性也掛載了上去,可是這個值並無使用validator
進行值的校驗,可能在Element3
開發人員可能爲了方便之後的拓展吧,若是原聲中native-type
添加其餘的值依賴組件庫的項目便可以直接使用,無需更改組件庫部分,同時也不但願組件庫去影響原生的某些屬性。github
筆者也看了一下文檔在Element3
中Button
的文檔中,提供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
在setup
對class
進行了統一的處理,那麼咱們就看下這部分的內容,方法中首先處理的是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; }); };
其實這裏的處理邏輯和處理button
的size
是差很少的,這裏對代碼就很少贅述了,這裏一樣是返回了所獲取到的值。這裏接收的再也不是elFormItem
的值,而是elForm
的值,經過這裏能夠得出,Element3
在elForm
傳入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.0
的Provide/Inject
,總體代碼思路清晰代碼結構簡單,都是咱們值得學習的地方。
哪有什麼歲月靜好,不過是有人替你負重前行。感謝爲Element3
默默付出的程序大佬們。
若是你們感興趣的話就點擊下方鏈接,Star
一下吧。