Vue組件開發(fā)小結(jié)

組件化是長(zhǎng)期開發(fā)過程中一個(gè)提煉精華的過程,目的主要是以下幾點(diǎn):

  1. 提高復(fù)用性
  2. 解耦
  3. 提升未來的開發(fā)效率

那么如何達(dá)到這樣的效果呢,我們可以分幾步來循序漸進(jìn)地完成。

下文主要是思路,想直接獲取代碼可轉(zhuǎn)戰(zhàn)ElementUI的Github去看源碼

一 組件的定義

組件從大類上可以分為兩種:

  • 基礎(chǔ)組件:例如ElementUI
  • 業(yè)務(wù)組件:通過基礎(chǔ)組件或者業(yè)務(wù)組件組合而成,與業(yè)務(wù)強(qiáng)相關(guān)甚至強(qiáng)綁定

二 組件的顆粒度

基礎(chǔ)組件的顆粒度爭(zhēng)議并不大,就是Button,Table等等
業(yè)務(wù)組件的顆粒度最大可以為一個(gè)feature,一個(gè)feature就是一個(gè)可以獨(dú)立上線特性,例如文章的評(píng)論點(diǎn)贊功能。我們可以想象有一個(gè)開關(guān),打開就有這個(gè)feature,關(guān)閉就沒有,且不會(huì)造成聯(lián)動(dòng)的影響。

三 組件的接口

  1. Vue的組件基本都是通過屬性來進(jìn)行配置,進(jìn)而控制組件的功能變化。因此開發(fā)組件之前我們就得明確定義變量是什么,明確組件需要開放的接口
  2. 我們需要理解每一個(gè)組件的核心功能是什么,可通過單一職責(zé)這樣的設(shè)計(jì)模式來考慮。組件的核心功能是不能發(fā)生變化的,這也是為了接口的向后兼容
  3. 對(duì)于業(yè)務(wù)組件,我們可否直接把一些常年不發(fā)生變化的數(shù)據(jù)和UI綁定在一起,從而刪減部分接口。大家不必?fù)?dān)心耦合性,解耦的前提是有被解耦的需求。

四 開發(fā)組件

1 UI規(guī)范

UI規(guī)范是組件開發(fā)的物理依據(jù),你得知道要做成什么樣子,你才能做。UI規(guī)范要對(duì)整套組件的各個(gè)視覺元素(長(zhǎng),寬,padding,margin,圓角,顏色,字體,字號(hào),邊框,圖標(biāo),陰影)有語意明確的定義和友好的標(biāo)注,這樣前端工程師們才能做到有法可依。

2 開發(fā)

舉例:
1.sass或less來寫樣式
2.重置樣式文件和樣式的公共變量文件(將視覺元素翻譯成代碼中的常量形成的文件),這是根據(jù)自己的UI規(guī)范來決定的
3.ES6的哪些特性不使用,用哪一個(gè)stage的babel來翻譯
4.需要引入的第三方包有哪些,這個(gè)也決定了最后打包出來組件js的大小
5.工程的目錄結(jié)構(gòu)

3 打包

對(duì)于Vue,我們通常使用的是webpack。具體配置這里不詳細(xì)講解,可以參考入門Webpack,看這篇就夠了,還有一個(gè)快速方法就是通過Vue-cli生成的模板工程來進(jìn)行更改。
接著我們要定義清楚我們的打包策略:

舉例:
1.所有的樣式打到一個(gè)文件
2.有fonts則單獨(dú)打出來
3.組件JS和VueJS不打在一起
4.非通用的第三方包需和組件打在一起

五 最佳實(shí)踐

以上四點(diǎn)是正式編寫組件代碼的前置工作?,F(xiàn)在我們通過elementUI的源碼來看一個(gè)最佳實(shí)踐,我們的例子是比較簡(jiǎn)單的面包屑,先看一下怎么去使用的這個(gè)組件:

用法.png

然后我們來看一下代碼如何實(shí)現(xiàn)的

<template>
  <span class="el-breadcrumb__item">
    <span class="el-breadcrumb__inner" ref="link" role="link">
      <slot></slot>
    </span>
    <i v-if="separatorClass" class="el-breadcrumb__separator" :class="separatorClass"></i>
    <span v-else class="el-breadcrumb__separator" role="presentation">{{separator}}</span>
  </span>
</template>
<script>
  export default {
    name: 'ElBreadcrumbItem',
    props: {
      to: {},
      replace: Boolean
    },
    data() {
      return {
        separator: '',
        separatorClass: ''
      };
    },

    inject: ['elBreadcrumb'],

    mounted() {
      this.separator = this.elBreadcrumb.separator;
      this.separatorClass = this.elBreadcrumb.separatorClass;
      let self = this;
      if (this.to) {
        let link = this.$refs.link;
        link.setAttribute('role', 'link');
        link.addEventListener('click', _ => {
          let to = this.to;
          self.replace ? self.$router.replace(to)
            : self.$router.push(to);
        });
      }
    }
  };
</script>

props中就是ElBreadcrumbItem暴露出來的兩個(gè)接口,也就是上文第三點(diǎn)提到的內(nèi)容,接口的值是從父組件傳過來的。我們?cè)倏匆幌翬lBreadcrumb,也就是父組件的代碼實(shí)現(xiàn)。

這里簡(jiǎn)單解釋一下inject:inject和provide是成對(duì)出現(xiàn)的,是vue@2.2.0的新特性。通過此種方法變可以直接調(diào)用提供provide的組件中的屬性了,總結(jié)就是依賴注入(DI)。

<template>
  <div class="el-breadcrumb" aria-label="Breadcrumb" role="navigation">
    <slot></slot>
  </div>
</template>
<script>
  export default {
    name: 'ElBreadcrumb',

    props: {
      separator: {
        type: String,
        default: '/'
      },
      separatorClass: {
        type: String,
        default: ''
      }
    },

    provide() {
      return {
        elBreadcrumb: this
      };
    },

    mounted() {
      const items = this.$el.querySelectorAll('.el-breadcrumb__item');
      if (items.length) {
        items[items.length - 1].setAttribute('aria-current', 'page');
      }
    }
  };
</script>

slot其實(shí)是專門留給ElBreadcrumbItem的插槽,實(shí)際上ElBreadcrumb不涉及什么UI,它也通過props暴露出來了兩個(gè)接口,這個(gè)兩個(gè)的值是使用者傳入的。我們可以看到,默認(rèn)的分隔符是'/',如果你在ElBreadcrumbItem中通過屬性傳入的分隔符是'+',那面包屑每一級(jí)中的分隔符也會(huì)是'+',注意一下代碼中的provide和上面的inject相對(duì)應(yīng)。最后就是讓組件可注冊(cè)

import ElBreadcrumb from './src/breadcrumb';

/* istanbul ignore next */
ElBreadcrumb.install = function(Vue) {
  Vue.component(ElBreadcrumb.name, ElBreadcrumb);
};

export default ElBreadcrumb;

通過給組件添加install方法,讓組件可被Vue.use方法在全局注冊(cè)??蓞⒖?a target="_blank" rel="nofollow">Vue官方文檔API

總結(jié)

本文簡(jiǎn)單梳理了一下組件開發(fā)的思路,重點(diǎn)在于組件開發(fā)的這些前置條件:

  • 定義組件
  • 劃分顆粒度
  • 理清組件的核心接口
  • 如何定義打包策略和UI規(guī)范

完成這幾點(diǎn),從代碼層面只是一小部分工作,但若把整個(gè)組件作為一個(gè)產(chǎn)品來看,就已經(jīng)完成了一半了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容