如何寫一個公共組件(sdk)

前言

關於前端中臺的一些事

愈來愈多的公司都有前端中臺,提及中臺,這個最先是從阿里在2015年提出的「大中臺,小前臺」戰略中延伸出來的。前端

通常來講公司隨着業務不斷髮現,業務線不斷增長,會出現各個業務線雖然業務不一樣,可是核心底層架構(項目搭建的相關腳手架,項目目錄,編譯,部署)和公共組件(地區選擇,日期,彈層,表單校驗等)都是一致的狀況。若是各個業務線在完成業務的同時還要本身搭建項目,開發各種組件,必然會致使重複開發、重複建設,效率低,產研資源浪費,進而影響產品上線時間。react

在競爭如此激烈的時代,爲了快速迭代產品,爲了公司能快速的發展,就須要一箇中間平臺去幫各業務線完成底層的相關搭建,公共框架組件的封裝。npm

在這個大背景下,做爲中颱的一名前端,職責就是開發維護供整個公司前端使用的一些公共組件(插件),也總結了相關經驗。後端

正文

思路與邏輯

  1. 在組件開發以前,須要根據需求考慮組件須要實現的功能,這些功能須要暴露出去。
  2. 設計組件,秉着「最簡單的調用,最靈活的擴展」原則,也就是使用者能夠傳入最少的配置參數完成組件調用展現,也能夠經過配置進行靈活的定製化。例如開發一個公共彈層組件,業務端既能夠只傳入文本進行簡單調用展現,也能夠擴展配置,實現一個更加定製,更加複雜的彈層。 例如antd的Modal組件。
  3. 咱們所開發的組件通常都會發布npm包,方便調用和維護。各個公司都有本身的npm, npm包的通常目錄以下,固然若是簡單的組件可能只有index.js,目錄根據實際設置就好。image.png
  4. 默認狀況調用的入口就是index.js, 多數組件是一個類,通常咱們在

舉例

  • 使用類的方式實現一個原生js的簡單訂閱發佈插件:
class EventListner{
    constructor(){
        // 單例模式保證此類只建立一次
        if (EventListner['EventListnerInstance']) {
        return EventListner['EventListnerInstance']
        }
        EventListner['EventListnerInstance'] = this;
        this.subscribeList = {} // 訂閱事件名稱
    }
    //訂閱
    on(evt, fn){
        if (typeof fn === 'function') {
            this.subscribeList[evt] = this.subscribeList[evt] || []
            this.subscribeList[evt].push(fn)
            // unique爲對比同一監聽事件的回調是否同樣,同樣則排除
            this.subscribeList[evt] = unique(this.subscribeList[evt], (item1, item2) => item1.toString() === item2.toString())
        }
    }
    // 發佈
    publish(...args) {
        const fns = this.subscribeList[args[0]]
        if (fns !== undefined) {
            const _args = args[1] || ''
            for (const fn in fns) {
                if (Object.prototype.hasOwnProperty.call(fns, fn)) {
                    fns[fn](_args)
                }
            }
        }
    }
    // 解綁事件
    off(ev, fn) {
        if (typeof ev !== 'string') {
            return
        }
        if (this.subscribeList.hasOwnProperty(ev)) {
            this.subscribeList[ev] = []
        }
        fn && fn()
    }
}
export default new EventListner();
  • 既支持組件方式能夠傳入子組件,又須要支持方法直接調用, 相似antd的Modal組件。
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
// 實現組件方式調用
class Dialog extends Component {
    componentDidMount() {
        this.appendDialog()
    }
    componentDidUpdate() {
        this.appendDialog()
    }
    appendDialog() {
        // 須要根據傳入的props處理渲染的相關邏輯
        ...
    }
    render() {
        return null
    }
}
// 將各配置進行類型檢查
Dialog.propTypes = {
    title:'', // 標題
    content:'', // 內容
    ...
}

// 實現方法直接調用
// 各類success, error,warning等都會走的邏輯,提出一個方法來
function confirm(props) {
    let _confirm
    if(!document.querySelector('dialog-container')){
        _confirm = document.createElement('div')
        _confirm.id = 'dialog-container'
        document.body.appendChild(_confirm)
    }
    ReactDOM.render(
        // 此處渲染一個彈層
        <DialogContent {...props} />,
        _confirm,
    )
}
// 此處只舉例其中一種彈層success,其餘error,confirm都相似只有圖標,按扭等不一樣
Dialog.success = function(props) {
    const config = {
        footer: false,
        width: 280,
        position: 'center',
        visible: true,
        closeBtn: false,
        ...props,
    },
    return confirm(config)
}
export default Dialog
  • 繼承,並改寫父類一些方法的sdk。

這一般是在某個底層sdk須要再包一層嵌套業務的邏輯時使用。好比說公司須要一個直播的服務,須要中臺的先後端配合提供,前端負責封裝sdk, 後端負責提供接口和服務,這時按照咱們以前的思路是能夠實現,可是隨着業務的擴展,當一個新興的業務線也須要一個直播服務,可是他們想要本身去搭建後端服務,前端底層邏輯與API接口是一致的。這時候咱們以前所寫的融入了一些業務邏輯的sdk就不能知足了。這種狀況咱們須要將底層邏輯與業務相關邏輯拆分爲兩個類,基類只提供基本的方法與調用要足夠純淨,繼承的子類去實現通用業務邏輯處理。這樣當業務邏輯層沒法知足時,能夠自行封裝子類去實現。設計模式

class Base{
    getSigniture(){
       this.getVideoSigniture()
    }
    play(){
    }
    pause(){
    }
    ...
}
class Child1 extends Base{
    getVideoSigniture(){
        // 此處自行實現該子類須要的邏輯
        ...
    }
}

經常使用到的一些設計模式

1, 單例模式。
當咱們建立的sdk或插件在使用中可能會被屢次實例化時,須要在咱們的sdk或插件的構造函數中處理,屢次實例化返回指向同一個對象的指針。數組

2, 發佈訂閱。
此類設計模式在im的sdk中經常用到,由於連接、接收消息等都是異步的,用戶須要去監聽連接成功、斷開,接受消息等事件antd

總結

其實業務前端在平時工做中一樣會須要封裝一些供本身業務端使用的公共組件或插件,方便多個項目同時使用,也方便後期維護。
以上均爲工做中的一些總結,還有不少須要改進和學習的地方,歡迎你們提出問題與建議。架構

相關文章
相關標籤/搜索