如何写一个公共组件(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

总结

其实业务前端在平时工做中一样会须要封装一些供本身业务端使用的公共组件或插件,方便多个项目同时使用,也方便后期维护。
以上均为工做中的一些总结,还有不少须要改进和学习的地方,欢迎你们提出问题与建议。架构

相关文章
相关标签/搜索