原來 Element 的元件原始碼還能這麼看

尤水就下也發表於2019-04-03

前言

作為一位有追求(但學不動)的前端開發者,我們肯定都曾想通過看元件庫的原始碼(本章以 Element 為例)來拔高自己的水平,也肯定都嘗試過,只是最終不了了之罷了。就像我也是這樣的?,到現在也只看了 1/6 ?,還是最簡單的那幾個元件。其實(對於功底一般的我們來說)看原始碼是需要時間和方法的:關於時間,我想每個星期(看自己安排)看一個元件就足以,不用全部看完,挑有代表性的看就行;關於方法就是我本章要重點講解的,這裡以 button 元件為例(因為它最簡單實用),希望你看完之後能夠有所啟發。當然啦,看原始碼之前其實還有一件很重要的事情要做,就是你應當要用過 Element 之類的元件庫,這點很重要,要先學會用,再去深究其原理。就像我給你一把鋸子(真是個湊合的比喻?),你不曾用過它,就想去搞懂鋸子是怎麼做的,你說你都不知道它的實際應用場景,又怎麼去設計好它呢,靠天馬行空麼。

哦,對了,雞湯一下,其實原始碼這東西只是聽起來玄乎,看起來迷茫,你只要稍微熟悉之後,它就變得很透明瞭,任你?宰割(解讀)。很多東西只是我們平時碰的比較少,因為陌生所以才覺得難。想想我們平時開發過程中寫的元件,那個也是原始碼啊,只不過寫的可能沒有那麼優雅罷了???。

Element 原始碼地址:github.com/ElemeFE/ele…
Element 文件:element-cn.eleme.io/#/zh-CN/com…

關於目錄

原來 Element 的元件原始碼還能這麼看
原來 Element 的元件原始碼還能這麼看
由於本文的重點是講解元件的具體思路,所以我們只要知道元件原始碼在哪裡就行了,至於整體目錄就結構先不說了,當然了,有興趣的同學們可以看一下?這篇文章:?:基於 vue-cli3 打造屬於自己的 UI 庫

怎麼看

這裡先簡要說下我看元件原始碼的方法,僅供大家參考,不喜勿噴哈?。
首先 Element 有幾個版本,我看的是基於 Vue 的版本,所以每個元件到底就是一個 vue 檔案,就和我們平時工作寫的程式碼一樣,寫好一個 vue 元件,然後在需要的頁面引入即可。不過更重要的是要知道如何寫好這個元件(健壯嗎,可擴充套件嗎,易維護嗎等)。一個 vue 元件一般可分為三部分,templatescriptstyle。在這裡我們就不考慮 style 了,直接在頁面引用 Element 的樣式就好,因為這不是我們主要關心的,我們只要知道 Element 的樣式一般是這樣(el-元件名--狀態,比如 el-button--primary)命名的就行。所以我們元件裡是沒有寫 style 部分的,這樣做能幫我們省下好多時間和精力。

// 直接在頁面中引入 Element 的樣式
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
複製程式碼

先看 template 部分

那麼接下來我們就先看看 template 的部分怎麼寫。其實這部分是很簡單的(對於這個元件來說?),我們可以先開啟 Element 文件看一下 button 的外觀樣式,再來寫這部分,它大概長下面這樣:

原來 Element 的元件原始碼還能這麼看
ok,假設你已經看過 button 元件的大部分外觀,接下來我們就可以在腦海中先想一下(抽離並化簡一下 html 結構的公共部分),大概就是一個 div(button 標籤)裡面包了一個 i 圖示和 span 文字這樣的結構,嗯好像是這樣,那就試著寫一下吧!(提示:Element 元件一般最外層的樣式都是用 el-元件名 包起來的)

<template>
  <button class="el-button">
    <i></i>
    <span></span>
  </button>
</template>
複製程式碼

看上面的結構像那麼回事,也簡單明瞭。不過,然後呢?。。。 然後就是我們的 script 部分啦,這個才是元件的靈魂所在,重中之重,也是需要我們去啃的部分。好在這個元件簡單,讓我們繼續往下看吧。

再看 script 部分

我們看這部分的時候,可能無從下手,但其實還是有點門道的。敲鑼啦???。。。。不管神馬元件,都有三個較為重要的組成部分:propseventslot,這三個部分是元件對內對外溝通的橋樑,使得元件變得靈活起來。所以這三個 api 在釋出之前一定構思好和確定好,因為後期再改就很難了,可能就是會牽一髮動全身那樣子。但後期對元件的處理其實不應該是這樣的效果,而應該是不影響和改動之前的 api,但又可以擴充套件和新增功能。ok?,就讓我們一個一個娓娓道來吧?。 首先看下 props 的部分,你需要在腦海中想象一下 button 元件的哪些內容是可變的(根據需要外部傳參的改變而改變),不用著急往下看,先好好想一下?。。。。
...
1)最明顯的就是 button 的背景色吧,這顯然是可變的,就是 type;
2)然後是有沒有圖示,就是 icon;
3)還有就是有沒有禁用,就是 disabled;
4)再來是有沒有圓角,就是 round;
5)尺寸大小也是可變的吧,就是 size;
6)好像按鈕還可以是文字的樣子,就是 plain;
....
好了,那我們就試著寫一下 props 部分吧!(注意:props 的部分最好用物件的寫法,這樣能夠對每個屬性進行自定義設定,相比陣列的寫法,更為規範嚴謹)。

<script>
export default {
  props: {
    type: {
      type: String,
      default: ''
    },
    size: {
      type: String,
      default: 'medium'
    },
    icon: {
      type: String,
      default: ''
    },
    disabled: Boolean,
    plain: Boolean,
    round: Boolean
  }
}
</script>
複製程式碼

接下來是 slot 部分啦,如果不懂 slot 用法的同學可以先出門左拐學習一下再來✋。很明顯,對於 button 元件來說,文字就是 slot 啦,所以 template 裡面的內容可以小改一下,程式碼如下:

<template>
  <button class="el-button">
    <i></i>
    <span><slot></slot></span>
  </button>
</template>
複製程式碼

然後是 event 部分,很顯然啦,按鈕能有什麼功能呢,就是點選嘛,沒了,所以它也就一個事件,就是當按鈕被點選的時候,我們需要觸發一個事件向上傳遞,也就是 $emit。於是乎,我們把事件新增到元件中,程式碼如下:

<template>
  <button
    class="el-button"
    @click="handleClick">
    <i></i>
    <span><slot></slot></span>
  </button>
</template>
<script>
export default {
  props: {
    ...
  },
  methods: {
    handleClick (e) {
      this.$emit('click', e);
    }
  }
}
</script>
複製程式碼

好像 event 的部分就那麼多,嗯,是的,比想象中的簡單✊。。。。

再看 template 部分

你以為元件寫完了,不,並沒有,你不覺得 template 裡面太空了麼,而且 props 這部分的屬性都還沒用上呢(只是宣告瞭一下),所以我們還需要完善點東西。。。 比如 slot 部分吧,通過 $slots.default 我們可以獲取到 slot 中的內容,不過這裡需要加個判斷,因為使用者可能沒有傳文字,那我們就不用渲染了; 又比如圖示 i 的部分,和 slot 一樣,有傳值我們才渲染,所以也加個判斷(這裡 icon 的值為 el-icon-圖示名 格式)。

<template>
  <button
    class="el-button"
    @click="handleClick">
    <i :class="icon" v-if="icon"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>
複製程式碼

再看 props 中的屬性,其實當中大部分都是用來控制樣式變化的,比如 typesizerounddisabledplain 等。。。所以就讓我們為元件加上些 class 吧。

<template>
  <button
    class="el-button"
    @click="handleClick"
    :disabled="disabled"
    :class="[
      type ? 'el-button--' + type : '',
      size ? 'el-button--' + size : '',
      {
        'is-disabled': disabled,
        'is-plain': plain,
        'is-round': round
      }
    ]">
    <i :class="icon" v-if="icon"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>
複製程式碼

至此我們就寫完了一個較為完整的 button 元件,是不是給人一種?這麼簡單的麼?的感覺,雖然它還不夠完善,但也覆蓋了原始碼 90% 的部分,剩下的 10% 大家可以自己去補充補充。其實元件主要還是要看你?思考?得有多全面,想的越多寫的越多。

結語

順著上面的思路,我們就可以有個較為明瞭的方法去看 Element 其他元件的原始碼(應該會輕鬆一些吧?)。當然這裡僅僅只是起一個拋磚引玉的作用,主要還是因為 button 元件確實簡單還實用,很適合敲門磚的角色,當然也許後面看到其它複雜的元件你就不會這樣想了?。但是不管怎麼說,好的開始是成功的一半,革命尚未成功,同志仍需努力。擼起袖子加油幹吧?!!!

相關文章