成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從 12.9K 的前端開(kāi)源項(xiàng)目我學(xué)到了啥?

開(kāi)發(fā)
阿寶哥帶領(lǐng)大家開(kāi)啟 BetterScroll 2.0 源碼的學(xué)習(xí)之旅。

[[343776]]

 接下來(lái)本文的重心將圍繞 插件化 的架構(gòu)設(shè)計(jì)展開(kāi),不過(guò)在分析 BetterScroll 2.0 插件化架構(gòu)之前,我們先來(lái)簡(jiǎn)單了解一下 BetterScroll。

一、BetterScroll 簡(jiǎn)介
BetterScroll 是一款重點(diǎn)解決移動(dòng)端(已支持 PC)各種滾動(dòng)場(chǎng)景需求的插件。它的核心是借鑒的 iscroll 的實(shí)現(xiàn),它的 API 設(shè)計(jì)基本兼容 iscroll,在 iscroll 的基礎(chǔ)上又?jǐn)U展了一些 feature 以及做了一些性能優(yōu)化。

BetterScroll 1.0 共發(fā)布了 30 多個(gè)版本,npm 月下載量 5 萬(wàn),累計(jì) star 數(shù) 12600+。那么為什么升級(jí) 2.0 呢?

  1. 做 v2 版本的初衷源于社區(qū)的一個(gè)需求: 
  2.  
  3. BetterScroll 能不能支持按需加載? 
  4. 來(lái)源于:BetterScroll 2.0 發(fā)布:精益求精,與你同行 

為了支持插件的按需加載,BetterScroll 2.0 采用了 插件化 的架構(gòu)設(shè)計(jì)。CoreScroll 作為最小的滾動(dòng)單元,暴露了豐富的事件以及鉤子,其余的功能都由不同的插件來(lái)擴(kuò)展,這樣會(huì)讓 BetterScroll 使用起來(lái)更加的靈活,也能適應(yīng)不同的場(chǎng)景。

下面是 BetterScroll 2.0 整體的架構(gòu)圖:

該項(xiàng)目采用的是 monorepos 的組織方式,使用 lerna 進(jìn)行多包管理,每個(gè)組件都是一個(gè)獨(dú)立的 npm 包:

與西瓜播放器一樣,BetterScroll 2.0 也是采用 插件化 的設(shè)計(jì)思想,CoreScroll 作為最小的滾動(dòng)單元,其余的功能都是通過(guò)插件來(lái)擴(kuò)展。比如長(zhǎng)列表中常見(jiàn)的上拉加載和下拉刷新功能,在 BetterScroll 2.0 中這些功能分別通過(guò) pull-up 和 pull-down 這兩個(gè)插件來(lái)實(shí)現(xiàn)。

插件化的好處之一就是可以支持按需加載,此外把獨(dú)立功能都拆分成獨(dú)立的插件,會(huì)讓核心系統(tǒng)更加穩(wěn)定,擁有一定的健壯性。

好的,簡(jiǎn)單介紹了一下 BetterScroll,接下來(lái)我們步入正題來(lái)分析一下這個(gè)項(xiàng)目中一些值得我們學(xué)習(xí)的地方。

二、開(kāi)發(fā)體驗(yàn)方面
2.1 更好的智能提示
BetterScroll 2.0 采用 TypeScript 進(jìn)行開(kāi)發(fā),為了讓開(kāi)發(fā)者在使用 BetterScroll 時(shí)能夠擁有較好的智能提示,BetterScroll 團(tuán)隊(duì)充分利用了 TypeScript 接口自動(dòng)合并的功能,讓開(kāi)發(fā)者在使用某個(gè)插件時(shí),能夠有對(duì)應(yīng)的 Options 提示以及 bs(BetterScroll 實(shí)例)能夠有對(duì)應(yīng)的方法提示。

2.1.1 智能插件 Options 提示

2.1.2 智能 BetterScroll 實(shí)例方法提示

接下來(lái),為了后面能更好地理解 BetterScroll 的設(shè)計(jì)思想,我們先來(lái)簡(jiǎn)單介紹一下插件化架構(gòu)。

三、插件化架構(gòu)簡(jiǎn)介
3.1 插件化架構(gòu)的概念
插件化架構(gòu)(Plug-in Architecture),是一種面向功能進(jìn)行拆分的可擴(kuò)展性架構(gòu),通常用于實(shí)現(xiàn)基于產(chǎn)品的應(yīng)用。插件化架構(gòu)模式允許你將其他應(yīng)用程序功能作為插件添加到核心應(yīng)用程序,從而提供可擴(kuò)展性以及功能分離和隔離。

插件化架構(gòu)模式包括兩種類(lèi)型的架構(gòu)組件:核心系統(tǒng)(Core System)和插件模塊(Plug-in modules)。應(yīng)用邏輯被分割為獨(dú)立的插件模塊和核心系統(tǒng),提供了可擴(kuò)展性、靈活性、功能隔離和自定義處理邏輯的特性。

圖中 Core System 的功能相對(duì)穩(wěn)定,不會(huì)因?yàn)闃I(yè)務(wù)功能擴(kuò)展而不斷修改,而插件模塊是可以根據(jù)實(shí)際業(yè)務(wù)功能的需要不斷地調(diào)整或擴(kuò)展。插件化架構(gòu)的本質(zhì)就是將可能需要不斷變化的部分封裝在插件中,從而達(dá)到快速靈活擴(kuò)展的目的,而又不影響整體系統(tǒng)的穩(wěn)定。

插件化架構(gòu)的核心系統(tǒng)通常提供系統(tǒng)運(yùn)行所需的最小功能集。插件模塊是獨(dú)立的模塊,包含特定的處理、額外的功能和自定義代碼,來(lái)向核心系統(tǒng)增強(qiáng)或擴(kuò)展額外的業(yè)務(wù)能力。通常插件模塊之間也是獨(dú)立的,也有一些插件是依賴(lài)于若干其它插件的。重要的是,盡量減少插件之間的通信以避免依賴(lài)的問(wèn)題。

3.2 插件化架構(gòu)的優(yōu)點(diǎn)
靈活性高:整體靈活性是對(duì)環(huán)境變化快速響應(yīng)的能力。由于插件之間的低耦合,改變通常是隔離的,可以快速實(shí)現(xiàn)。
可測(cè)試性:插件可以獨(dú)立測(cè)試,也很容易被模擬,不需修改核心系統(tǒng)就可以演示或構(gòu)建新特性的原型。
性能高:雖然插件化架構(gòu)本身不會(huì)使應(yīng)用高性能,但通常使用插件化架構(gòu)構(gòu)建的應(yīng)用性能都還不錯(cuò),因?yàn)榭梢宰远x或者裁剪掉不需要的功能。
介紹完插件化架構(gòu)相關(guān)的基礎(chǔ)知識(shí),接下來(lái)我們來(lái)分析一下 BetterScroll 2.0 是如何設(shè)計(jì)插件化架構(gòu)的。

四、BetterScroll 插件化架構(gòu)實(shí)現(xiàn)
對(duì)于插件化的核心系統(tǒng)設(shè)計(jì)來(lái)說(shuō),它涉及三個(gè)關(guān)鍵點(diǎn):插件管理、插件連接和插件通信。下面我們將圍繞這三個(gè)關(guān)鍵點(diǎn)來(lái)逐步分析 BetterScroll 2.0 是如何實(shí)現(xiàn)插件化架構(gòu)。

4.1 插件管理
為了統(tǒng)一管理內(nèi)置的插件,也方便開(kāi)發(fā)者根據(jù)業(yè)務(wù)需求開(kāi)發(fā)符合規(guī)范的自定義插件。BetterScroll 2.0 約定了統(tǒng)一的插件開(kāi)發(fā)規(guī)范。BetterScroll 2.0 的插件需要是一個(gè)類(lèi),并且具有以下特性:

1.靜態(tài)的 pluginName 屬性;

2.實(shí)現(xiàn) PluginAPI 接口(當(dāng)且僅當(dāng)需要把插件方法代理至 bs);

3.constructor 的第一個(gè)參數(shù)就是 BetterScroll 實(shí)例 bs,你可以通過(guò) bs 的 事件 或者 鉤子 來(lái)注入自己的邏輯。

這里為了直觀地理解以上的開(kāi)發(fā)規(guī)范,我們將以?xún)?nèi)置的 PullUp 插件為例,來(lái)看一下它是如何實(shí)現(xiàn)上述規(guī)范的。PullUp 插件為 BetterScroll 擴(kuò)展上拉加載的能力。

顧名思義,靜態(tài)的 pluginName 屬性表示插件的名稱(chēng),而 PluginAPI 接口表示插件實(shí)例對(duì)外提供的 API 接口,通過(guò) PluginAPI 接口可知它支持 4 個(gè)方法:

finishPullUp(): void:結(jié)束上拉加載行為;
openPullUp(config?: PullUpLoadOptions): void:動(dòng)態(tài)開(kāi)啟上拉功能;
closePullUp(): void:關(guān)閉上拉加載功能;
autoPullUpLoad(): void:自動(dòng)執(zhí)行上拉加載。
插件通過(guò)構(gòu)造函數(shù)注入 BetterScroll 實(shí)例 bs,之后我們就可以通過(guò) bs 的事件或者鉤子來(lái)注入自己的邏輯。那么為什么要注入 bs 實(shí)例?如何利用 bs 實(shí)例?這里我們先記住這些問(wèn)題,后面我們?cè)賮?lái)分析它們。

4.2 插件連接
核心系統(tǒng)需要知道當(dāng)前有哪些插件可用,如何加載這些插件,什么時(shí)候加載插件。常見(jiàn)的實(shí)現(xiàn)方法是插件注冊(cè)表機(jī)制。核心系統(tǒng)提供插件注冊(cè)表(可以是配置文件,也可以是代碼,還可以是數(shù)據(jù)庫(kù)),插件注冊(cè)表含有每個(gè)插件模塊的信息,包括它的名字、位置、加載時(shí)機(jī)(啟動(dòng)就加載,或是按需加載)等。

這里我們以前面提到的 PullUp 插件為例,來(lái)看一下如何注冊(cè)和使用該插件。首先你需要使用以下命令安裝 PullUp 插件:

  1. $ npm install @better-scroll/pull-up --save 

成功安裝完 pullup 插件之后,你需要通過(guò) BScroll.use 方法來(lái)注冊(cè)插件:

  1. import BScroll from '@better-scroll/core' 
  2. import Pullup from '@better-scroll/pull-up' 
  3.  
  4. BScroll.use(Pullup) 

然后,實(shí)例化 BetterScroll 時(shí)需要傳入 PullUp 插件的配置項(xiàng)。

  1. new BScroll('.bs-wrapper', { 
  2.   pullUpLoad: true 
  3. }) 

現(xiàn)在我們已經(jīng)知道通過(guò) BScroll.use 方法可以注冊(cè)插件,那么該方法內(nèi)部做了哪些處理?要回答這個(gè)問(wèn)題,我們來(lái)看一下對(duì)應(yīng)的源碼:

  1. // better-scroll/packages/core/src/BScroll.ts 
  2. export const BScroll = (createBScroll as unknown) as BScrollFactory 
  3. createBScroll.use = BScrollConstructor.use 

在 BScroll.ts 文件中, BScroll.use 方法指向的是 BScrollConstructor.use 靜態(tài)方法,該方法的實(shí)現(xiàn)如下:

  1. export class BScrollConstructor<O = {}> extends EventEmitter { 
  2.   static plugins: PluginItem[] = [] 
  3.   static pluginsMap: PluginsMap = {} 
  4.  
  5.   static use(ctor: PluginCtor) { 
  6.     const name = ctor.pluginName 
  7.     const installed = BScrollConstructor.plugins.some
  8.       (plugin) => ctor === plugin.ctor 
  9.     ) 
  10.     // 省略部分代碼 
  11.     if (installed) return BScrollConstructor 
  12.     BScrollConstructor.pluginsMap[name] = true 
  13.     BScrollConstructor.plugins.push({ 
  14.       name
  15.       applyOrder: ctor.applyOrder, 
  16.       ctor, 
  17.     }) 
  18.     return BScrollConstructor 
  19.   } 

通過(guò)觀察以上代碼,可知 use 方法接收一個(gè)參數(shù),該參數(shù)的類(lèi)型是 PluginCtor,用于描述插件構(gòu)造函數(shù)的特點(diǎn)。PluginCtor 類(lèi)型的具體聲明如下所示:

  1. interface PluginCtor { 
  2.   pluginName: string 
  3.   applyOrder?: ApplyOrder 
  4.   new (scroll: BScroll): any 

當(dāng)我們調(diào)用 BScroll.use(Pullup) 方法時(shí),會(huì)先獲取當(dāng)前插件的名稱(chēng),然后判斷當(dāng)前插件是否已經(jīng)安裝過(guò)了。如果已經(jīng)安裝則直接返回 BScrollConstructor 對(duì)象,否則會(huì)對(duì)插件進(jìn)行注冊(cè)。即把當(dāng)前插件的信息分別保存到 pluginsMap({}) 和 plugins([]) 對(duì)象中:

另外調(diào)用 use 靜態(tài)方法后,會(huì)返回 BScrollConstructor 對(duì)象,這是為了支持鏈?zhǔn)秸{(diào)用:

  1. BScroll.use(MouseWheel) 
  2.   .use(ObserveDom) 
  3.   .use(PullDownRefresh) 
  4.   .use(PullUpLoad) 

現(xiàn)在我們已經(jīng)知道 BScroll.use 方法內(nèi)部是如何注冊(cè)插件的,注冊(cè)插件只是第一步,要使用已注冊(cè)的插件,我們還需要在實(shí)例化 BetterScroll 時(shí)傳入插件的配置項(xiàng),從而進(jìn)行插件的初始化。對(duì)于 PullUp 插件,我們通過(guò)以下方式進(jìn)行插件的初始化。

  1. new BScroll('.bs-wrapper', { 
  2.   pullUpLoad: true 
  3. }) 

所以想了解插件是如何連接到核心系統(tǒng)并進(jìn)行插件初始化,我們就需要來(lái)分析一下 BScroll 構(gòu)造函數(shù):

  1. // packages/core/src/BScroll.ts 
  2. export const BScroll = (createBScroll as unknown) as BScrollFactory 
  3.  
  4. export function createBScroll<O = {}>( 
  5.   el: ElementParam, 
  6.   options?: Options & O 
  7. ): BScrollConstructor & UnionToIntersection<ExtractAPI<O>> { 
  8.   const bs = new BScrollConstructor(el, options) 
  9.   return (bs as unknown) as BScrollConstructor & 
  10.     UnionToIntersection<ExtractAPI<O>> 

在 createBScroll 工廠(chǎng)方法內(nèi)部會(huì)通過(guò) new 關(guān)鍵字調(diào)用 BScrollConstructor 構(gòu)造函數(shù)來(lái)創(chuàng)建 BetterScroll 實(shí)例。因此接下來(lái)的重點(diǎn)就是分析 BScrollConstructor 構(gòu)造函數(shù):

  1. // packages/core/src/BScroll.ts 
  2. export class BScrollConstructor<O = {}> extends EventEmitter { 
  3.   constructor(el: ElementParam, options?: Options & O) { 
  4.     const wrapper = getElement(el) 
  5.     // 省略部分代碼 
  6.     this.plugins = {} 
  7.     this.hooks = new EventEmitter([...]) 
  8.     this.init(wrapper) 
  9.   } 
  10.    
  11.   private init(wrapper: MountedBScrollHTMLElement) { 
  12.     this.wrapper = wrapper 
  13.     // 省略部分代碼 
  14.     this.applyPlugins() 
  15.   } 

通過(guò)閱讀 BScrollConstructor 的源碼,我們發(fā)現(xiàn)在 BScrollConstructor 構(gòu)造函數(shù)內(nèi)部會(huì)調(diào)用 init 方法進(jìn)行初始化,而在 init 方法內(nèi)部會(huì)進(jìn)一步調(diào)用 applyPlugins 方法來(lái)應(yīng)用已注冊(cè)的插件:

  1. // packages/core/src/BScroll.ts 
  2. export class BScrollConstructor<O = {}> extends EventEmitter {   
  3.   private applyPlugins() { 
  4.     const options = this.options 
  5.     BScrollConstructor.plugins 
  6.       .sort((a, b) => { 
  7.         const applyOrderMap = { 
  8.           [ApplyOrder.Pre]: -1, 
  9.           [ApplyOrder.Post]: 1, 
  10.         } 
  11.         const aOrder = a.applyOrder ? applyOrderMap[a.applyOrder] : 0 
  12.         const bOrder = b.applyOrder ? applyOrderMap[b.applyOrder] : 0 
  13.         return aOrder - bOrder 
  14.       }) 
  15.       .forEach((item: PluginItem) => { 
  16.         const ctor = item.ctor 
  17.     // 當(dāng)啟用指定插件的時(shí)候且插件構(gòu)造函數(shù)的類(lèi)型是函數(shù)的話(huà),再創(chuàng)建對(duì)應(yīng)的插件 
  18.         if (options[item.name] && typeof ctor === 'function') { 
  19.           this.plugins[item.name] = new ctor(this) 
  20.         } 
  21.       }) 
  22.   } 

在 applyPlugins 方法內(nèi)部會(huì)根據(jù)插件設(shè)置的順序進(jìn)行排序,然后會(huì)使用 bs 實(shí)例作為參數(shù)調(diào)用插件的構(gòu)造函數(shù)來(lái)創(chuàng)建插件,并把插件的實(shí)例保存到 bs 實(shí)例內(nèi)部的 plugins({}) 屬性中。

到這里我們已經(jīng)介紹了插件管理和插件連接,下面我們來(lái)介紹最后一個(gè)關(guān)鍵點(diǎn) —— 插件通信。

4.3 插件通信
插件通信是指插件間的通信。雖然設(shè)計(jì)的時(shí)候插件間是完全解耦的,但實(shí)際業(yè)務(wù)運(yùn)行過(guò)程中,必然會(huì)出現(xiàn)某個(gè)業(yè)務(wù)流程需要多個(gè)插件協(xié)作,這就要求兩個(gè)插件間進(jìn)行通信;由于插件之間沒(méi)有直接聯(lián)系,通信必須通過(guò)核心系統(tǒng),因此核心系統(tǒng)需要提供插件通信機(jī)制。

這種情況和計(jì)算機(jī)類(lèi)似,計(jì)算機(jī)的 CPU、硬盤(pán)、內(nèi)存、網(wǎng)卡是獨(dú)立設(shè)計(jì)的配置,但計(jì)算機(jī)運(yùn)行過(guò)程中,CPU 和內(nèi)存、內(nèi)存和硬盤(pán)肯定是有通信的,計(jì)算機(jī)通過(guò)主板上的總線(xiàn)提供了這些組件之間的通信功能。

同樣,對(duì)于插件化架構(gòu)的系統(tǒng)來(lái)說(shuō),通常核心系統(tǒng)會(huì)以事件總線(xiàn)的形式提供插件通信機(jī)制。提到事件總線(xiàn),可能有一些小伙伴會(huì)有一些陌生。但如果說(shuō)是使用了 發(fā)布訂閱模式 的話(huà),應(yīng)該就很容易理解了。這里阿寶哥不打算在展開(kāi)介紹發(fā)布訂閱模式,只用一張圖來(lái)回顧一下該模式。

對(duì)于 BetterScroll 來(lái)說(shuō),它的核心是 BScrollConstructor 類(lèi),該類(lèi)繼承了 EventEmitter 事件派發(fā)器:

  1. // packages/core/src/BScroll.ts 
  2. export class BScrollConstructor<O = {}> extends EventEmitter {   
  3.   constructor(el: ElementParam, options?: Options & O) { 
  4.     this.hooks = new EventEmitter([ 
  5.       'refresh'
  6.       'enable'
  7.       'disable'
  8.       'destroy'
  9.       'beforeInitialScrollTo'
  10.       'contentChanged'
  11.     ]) 
  12.     this.init(wrapper) 
  13.   } 

EventEmitter 類(lèi)是由 BetterScroll 內(nèi)部提供的,它的實(shí)例將會(huì)對(duì)外提供事件總線(xiàn)的功能,而該類(lèi)對(duì)應(yīng)的 UML 類(lèi)圖如下所示:

講到這里我們就可以來(lái)回答前面留下的第一個(gè)問(wèn)題:“那么為什么要注入 bs 實(shí)例?”。因?yàn)?bs(BScrollConstructor)實(shí)例的本質(zhì)也是一個(gè)事件派發(fā)器,在創(chuàng)建插件時(shí),注入 bs 實(shí)例是為了讓插件間能通過(guò)統(tǒng)一的事件派發(fā)器進(jìn)行通信。

第一個(gè)問(wèn)題我們已經(jīng)知道答案了,接下來(lái)我們來(lái)看第二個(gè)問(wèn)題:”如何利用 bs 實(shí)例?“。要回答這個(gè)問(wèn)題,我們將繼續(xù)以 PullUp 插件為例,來(lái)看一下該插件內(nèi)部是如何利用 bs 實(shí)例進(jìn)行消息通信的。

  1. export default class PullUp implements PluginAPI { 
  2.   static pluginName = 'pullUpLoad' 
  3.   constructor(public scroll: BScroll) { 
  4.     this.init() 
  5.   } 

在 PullUp 構(gòu)造函數(shù)中,bs 實(shí)例會(huì)被保存到 PullUp 實(shí)例內(nèi)部的 scroll 屬性中,之后在 PullUp 插件內(nèi)部就可以通過(guò)注入的 bs 實(shí)例來(lái)進(jìn)行事件通信。比如派發(fā)插件的內(nèi)部事件,在 PullUp 插件中,當(dāng)距離滾動(dòng)到底部小于 threshold 值時(shí),觸發(fā)一次 pullingUp 事件:

  1. private checkPullUp(pos: { x: number; y: number }) { 
  2.   const { threshold } = this.options 
  3.   if (...) { 
  4.       this.pulling = true 
  5.       // 省略部分代碼 
  6.       this.scroll.trigger(PULL_UP_HOOKS_NAME) // 'pullingUp' 
  7.   } 

知道如何利用 bs 實(shí)例派發(fā)事件之后,我們?cè)賮?lái)看一下在插件內(nèi)部如何利用它來(lái)監(jiān)聽(tīng)插件所感興趣的事件

  1. // packages/pull-up/src/index.ts 
  2. export default class PullUp implements PluginAPI { 
  3.   static pluginName = 'pullUpLoad' 
  4.   constructor(public scroll: BScroll) { 
  5.     this.init() 
  6.   } 
  7.  
  8.   private init() { 
  9.     this.handleBScroll() 
  10.     this.handleOptions(this.scroll.options.pullUpLoad) 
  11.     this.handleHooks() 
  12.     this.watch() 
  13.   } 

在 PullUp 構(gòu)造函數(shù)中會(huì)調(diào)用 init 方法進(jìn)行插件初始化,而在 init 方法內(nèi)部會(huì)分別調(diào)用不同的方法執(zhí)行不同的初始化操作,這里跟事件相關(guān)的是 handleHooks 方法,該方法的實(shí)現(xiàn)如下:

  1. private handleHooks() { 
  2.   this.hooksFn = [] 
  3.   // 省略部分代碼 
  4.   this.registerHooks( 
  5.     this.scroll.hooks, 
  6.     this.scroll.hooks.eventTypes.contentChanged, 
  7.     () => { 
  8.       this.finishPullUp() 
  9.     } 
  10.   ) 

很明顯在 handleHooks 方法內(nèi)部,會(huì)進(jìn)一步調(diào)用 registerHooks 方法來(lái)注冊(cè)鉤子:

  1. private registerHooks(hooks: EventEmitter, name: string, handler: Function) { 
  2.   hooks.on(name, handler, this) 
  3.   this.hooksFn.push([hooks, name, handler]) 

通過(guò)觀察 registerHooks 方法的簽名可知,它支持 3 個(gè)參數(shù),第 1 個(gè)參數(shù)是 EventEmitter 對(duì)象,而另外 2 個(gè)參數(shù)分別表示事件名和事件處理器。在 registerHooks 方法內(nèi)部,它就是簡(jiǎn)單地通過(guò) hooks 對(duì)象來(lái)監(jiān)聽(tīng)指定的事件。

那么 this.scroll.hooks 對(duì)象是什么時(shí)候創(chuàng)建的呢?在 BScrollConstructor 構(gòu)造函數(shù)中我們找到了答案。

  1. // packages/core/src/BScroll.ts 
  2. export class BScrollConstructor<O = {}> extends EventEmitter { 
  3.   constructor(el: ElementParam, options?: Options & O) { 
  4.     // 省略部分代碼 
  5.     this.hooks = new EventEmitter([ 
  6.       'refresh'
  7.       'enable'
  8.       'disable'
  9.       'destroy'
  10.       'beforeInitialScrollTo'
  11.       'contentChanged'
  12.     ])  
  13.   } 

很明顯 this.hooks 也是一個(gè) EventEmitter 對(duì)象,所以可以通過(guò)它來(lái)進(jìn)行事件處理。好的,插件通信的內(nèi)容就先介紹到這里,下面我們用一張圖來(lái)總結(jié)一下該部分的內(nèi)容:

介紹完 BetterScroll 插件化架構(gòu)的實(shí)現(xiàn),最后我們來(lái)簡(jiǎn)單聊一下 BetterScroll 項(xiàng)目工程化方面的內(nèi)容。

五、工程化方面
在工程化方面,BetterScroll 使用了業(yè)內(nèi)一些常見(jiàn)的解決方案:

lerna:Lerna 是一個(gè)管理工具,用于管理包含多個(gè)軟件包(package)的 JavaScript 項(xiàng)目。
prettier:Prettier 中文的意思是漂亮的、美麗的,是一個(gè)流行的代碼格式化的工具。
tslint:TSLint 是可擴(kuò)展的靜態(tài)分析工具,用于檢查 TypeScript 代碼的可讀性,可維護(hù)性和功能性錯(cuò)誤。
commitizen & cz-conventional-changelog:用于幫助我們生成符合規(guī)范的 commit message。
husky:husky 能夠防止不規(guī)范代碼被 commit、push、merge 等等。
jest:Jest 是由 Facebook 維護(hù)的 JavaScript 測(cè)試框架。
coveralls:用于獲取 Coveralls.io 的覆蓋率報(bào)告,并在 README 文件中添加一個(gè)不錯(cuò)的覆蓋率按鈕。
vuepress:Vue 驅(qū)動(dòng)的靜態(tài)網(wǎng)站生成器,它用于生成 BetterScroll 2.0 的文檔。
因?yàn)楸疚牡闹攸c(diǎn)不在工程化,所以上面阿寶哥只是簡(jiǎn)單羅列了 BetterScroll 在工程化方面使用的開(kāi)源庫(kù)。如果你對(duì) BetterScroll 項(xiàng)目也感興趣的話(huà),可以看看項(xiàng)目中的 package.json 文件,并重點(diǎn)看一下項(xiàng)目中 npm scripts 的配置。

 

 

責(zé)任編輯:姜華 來(lái)源: 全棧修仙之路
相關(guān)推薦

2021-10-25 05:43:40

前端技術(shù)編程

2021-03-09 09:55:02

Vuejs前端代碼

2020-02-22 15:01:51

后端前端開(kāi)發(fā)

2020-07-07 08:52:16

機(jī)器學(xué)習(xí)機(jī)器學(xué)習(xí)工具人工智能

2022-03-27 09:06:04

React類(lèi)型定義前端

2016-01-18 10:06:05

編程

2020-12-31 10:47:03

開(kāi)發(fā)Vuejs技術(shù)

2021-04-15 08:15:27

Vue.js源碼方法

2024-04-12 08:54:13

從庫(kù)數(shù)據(jù)庫(kù)應(yīng)用

2020-11-04 07:13:57

數(shù)據(jù)工程代碼編程

2020-02-22 14:49:30

畢業(yè)入職半年感受

2021-07-28 07:01:09

薅羊毛架構(gòu)Vue+SSR

2021-01-02 09:48:13

函數(shù)運(yùn)算js

2020-10-30 12:40:04

Reac性能優(yōu)化

2019-08-27 10:49:30

跳槽那些事兒技術(shù)Linux

2013-06-27 10:31:39

2019-08-16 17:14:28

跳槽那些事兒技術(shù)Linux

2011-10-18 11:43:25

UNIXC語(yǔ)言丹尼斯·里奇

2015-06-29 13:47:19

創(chuàng)業(yè)創(chuàng)業(yè)智慧

2023-06-06 08:14:18

核心Docker應(yīng)用程序
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 成人3d动漫一区二区三区91 | 日韩欧美视频 | 精品欧美一区二区三区久久久 | 欧美αv | 综合久久综合久久 | 午夜电影合集 | 91污在线 | 免费在线观看成人 | 精精精精xxxx免费视频 | 久久aⅴ乱码一区二区三区 亚洲国产成人精品久久久国产成人一区 | 亚洲www.| 亚洲欧美日韩高清 | 日本中文字幕一区 | 日韩精品一区二区三区老鸭窝 | 久久综合888 | 91视频大全 | 啪啪网页 | 九九综合九九 | 亚洲精品日韩一区二区电影 | 精品亚洲91| 一区二区三区不卡视频 | 午夜精品久久久久99蜜 | 久久久激情视频 | 九九热在线观看视频 | 国际精品鲁一鲁一区二区小说 | 美国一级黄色片 | 免费在线观看成人 | 亚洲精品日韩一区二区电影 | 四虎网站在线观看 | 欧美综合一区二区三区 | 国产三区视频在线观看 | 久久精品国产99国产精品亚洲 | 精品国产乱码久久久久久蜜柚 | 国产精品一区在线观看 | 粉嫩一区二区三区四区公司1 | 久久中文字幕在线 | 91美女在线观看 | 国产一区久久精品 | 成人在线电影网站 | 在线视频91 | 九九久久国产精品 |