要看源碼就得從最簡單的開始,button夠簡單的了,就從他開始吧。
安裝依賴后源碼目錄在:node_modules/element-ui/packages中,可以看到這里的文件夾命名是不是很熟悉,就是我們平時寫的組件名,打開任何一個文件夾,都有一個src文件夾和一個index.js,src文件夾放組件,index.js用於注冊組件
下面來看具體的button源碼如何寫的:
分析從三個方面着手:DOM結構,數據屬性,事件
DOM結構:
按鈕的DOM結構很簡單,要顯示成什么樣子就由css樣式及一些自帶的屬性決定了,這些就交給數據屬性來控制
<button></button>
數據屬性:
按鈕的樣式,大小,顯示內容,類型等都需要通過數據屬性來控制,這些數據屬性分兩塊:
a、直接引用props
b、引用computed的屬性
直接引用props的數據大家都能理解,為什么還用到computed呢?
這里就涉及到provider/inject,
provider/inject:簡單的來說就是在父組件中通過provider來提供變量,然后在子組件中通過inject來注入變量。注意官方文檔有一句話“向其所有子孫后代注入一個依賴,不論組件層次有多深,並在起上下游關系成立的時間里始終生效”,這樣看來就明顯了,父組件提供的屬性只能在直接子組件中獲取到,孫組件就獲取不到,provide提供的屬性就解決了這個問題。
為什么用到computed?答案就很明顯了,防止全局設置/父組件的屬性,孫組件獲取不到
Vue.use(Element, { size: Cookies.get('size') || 'medium' // set element-ui default size })
有了provider/inject,這里配置的size才能全局起作用。
事件:
這里涉及到父子組件通信,子組件向父組件發消息可以用emit實現,父組件監聽即可,一般情況下父組件監聽的事件名都是自定義的,這里特殊了點,父組件直接監聽了“click”事件,誰讓button通常就一個點擊事件呢
index.js:
js的作用很簡單,注冊組件並導出
最后:
源碼DOM結構上有這樣一句:
<span v-if="$slots.default"><slot></slot></span>
我們知道插槽有具名插槽和不具名插槽,“$slots.default”指代的就是不具名插槽。為什么要這么寫,而不是:
<span><slot></slot></span>
這里其實是一個很細心的點,如果<el-button></el-button>不寫內容,將會少一個span節點,渲染后的DOM是這樣的
<button data-v-06af20c4="" type="button" class="el-button el-button--default el-button--medium"></button>
如果去掉v-if="$slots.default",渲染后將是這樣的
<button data-v-06af20c4="" type="button" class="el-button el-button--default el-button--medium"><span></span></button>
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
除了學知識,我們還可以從源碼中學到一點規范:
: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做了歸類,boolean類型的歸為了一類,放到對象中,我們是不是也可以這樣寫,讓代碼更整齊呢