【DoKit&北大專題】-讀小程序源代碼(二)

專題背景

近幾年隨着開源在國內的蓬勃發展,一些高校也開始探索讓開源走進校園,讓同窗們在學生時期就感覺到開源的魅力,這也是高校和國內的頭部互聯網企業共同嘗試的全新教學模式。本專題會記錄這段時間內學生們的學習成果。html

更多專題背景參考:【DoKit&北大專題】緣起前端

系列文章

【DoKit&北大專題】緣起json

【DoKit&北大專題】-讀小程序源代碼(一)小程序

【DoKit&北大專題】-讀小程序源代碼(二)微信小程序

原文

第一篇文章裏咱們將Dokit的模塊引入到了本身的小程序項目中,那麼接下來就是正式的閱讀Dokit的源代碼了。api

1、微信小程序自定義組件概述

DoKit模塊是由多個自定義組件構成的,所以在閱讀源碼以前,咱們須要先簡單的瞭解一下微信小程序自定義組件的基本知識。 微信小程序能夠說是由多個page頁面構成的,而每一個page頁面是由多個組件構成的,其中包括微信的原生組件,也包括了用戶的自定義組件。服務器

小程序構成.png

自定義組件的構成與Page頁面的構成很是相似,都具備4個文件:js、json、wxml、wxss。微信

  • js文件:頁面/自定義組件的邏輯文件
  • wxml文件:頁面/自定義組件的結構文件,能夠類比HTML,但沒有HTML的div、p等標籤,取而代之的是微信小程序的各類組件,如view、button等
  • wxss文件:頁面/自定義組件的樣式文件,能夠類比CSS,但自定義組件內的wxss文件不能使用ID選擇器、屬性選擇器和標籤名選擇器
  • json文件:頁面/自定義組件的配置文件,對於頁面,能夠在這裏設置是否使用自定義組件;對於自定義組件,設置是否使用自定義組件、更重要的是須要在這裏聲明該模塊爲自定義組件

引用自定義組件

在想要引用組件的page界面或自定義組件的json文件裏聲明:(自定義組件裏能夠再引用其餘的自定義組件)markdown

{
  "usingComponents": {
    "dokit": "../../dist/index/index"
  }
}
複製代碼

聲明模塊爲自定義組件

在自定義組件的json文件裏聲明:app

{
  "component": true,
  "usingComponents": {
    "back": "../../components/back/back"
  }
}
複製代碼

2、項目組織結構概述

如圖所示,Dokit的項目主體在dist文件夾

項目目錄.png

咱們先來了解一下該項目的目錄分佈,有助於咱們對項目有個總體的把控:

  • assets ——裏面有img文件夾,存儲icon等圖片資源

  • components ——Dokit最核心的部分,包括了八個自定義組件

    • apimock —— 數據模擬功能的自定義組件
    • appinformation —— App信息功能的自定義組件
    • back —— 用來返回的自定義組件,該組件並非Dokit的功能組件,但它被除了index以外全部的自定義組件調用,經過該組件返回到小程序page界面
    • debug —— 起到主菜單功能的自定義組件,羅列了Dokit的各類功能
    • h5door —— h5任意門功能的自定義組件
    • httpinjector ——請求注射功能的自定義組件
    • positionsimulation —— 位置模擬功能的自定義組件
    • storage —— 存儲管理功能的自定義組件
  • index —— Dokit入口的自定義組件,將Dokit引入本身項目中時,就是在目標page頁面中引入這個component

  • logs —— 與新建微信小程序時的樣例程序中的logspage頁面相同,查看程序啓動日誌,目前不知道Dokit中這個部分有什麼用

  • utils —— 裏面有兩個文件,imgbase64.js是用來將Dokit各類圖標轉換成base64格式的;util.js內存儲了一些經常使用接口函數,包括時間輸出、跳轉頁面、深拷貝等

在這裏簡要解釋一下什麼是base64格式的圖片:

base64格式是一種將二進制轉換成字符的編碼格式,而圖片的base64編碼就是將一副圖片的數據編碼成字符串; 這樣前端(如HTML或WXML)能夠直接利用編碼後的字符串直接轉換成圖片。針對各類體積小的圖片,使用base64格式能夠減小向服務器下載圖片的請求; 但要注意的是經過base64編碼後字符串的體積大小每每會比圖片自己要大,所以僅適用於體積小的,不常常更改的圖片。

更詳細的base64編碼信息能夠參考這篇文章

在簡單的瞭解了項目的目錄分佈後,咱們從Dokit的入口組件index開始,逐步閱讀源碼。 在閱讀源代碼以前先肯定一下咱們的閱讀順序,自定義組件有四個文件,咱們先閱讀.json.wxml.wxss文件,將.js文件穿插其中。

3、Dokit的入口組件

還記得咱們最初給本身的小程序項目中引入Dokit模塊的時候,在相應頁面的page.json文件中添加了如下語句:

"usingComponents": {
    "dokit": "../../dist/index/index"
  }
複製代碼

咱們當時引入的自定義組件就是dist文件夾下的index組件,這個組件就是Dokit的入口組件。先來看看這個組件的json文件,肯定它引用了什麼組件:

{
  "component": true,
  "navigationBarTitleText": "",
  "usingComponents": {
    "debug": "../components/debug/debug",
    "appinformation": "../components/appinformation/appinformation",
    "positionsimulation": "../components/positionsimulation/positionsimulation",
    "storage": "../components/storage/storage",
    "h5door": "../components/h5door/h5door",
    "httpinjector": "../components/httpinjector/httpinjector",
    "apimock": "../components/apimock/apimock"
  }
}
複製代碼

能夠看到這個組件引用了components文件夾中的全部Dokit的功能組件,接着看.wxml文件肯定它的結構/模版,是如何調用到了這麼多組件的:

<block wx:if="{{ curCom!= 'dokit' }}">
    <debug wx:if="{{ curCom === 'debug' }}" bindtoggle="tooggleComponent"></debug>
    <appinformation wx:if="{{ curCom === 'appinformation' }}" bindtoggle="tooggleComponent"></appinformation>
    <positionsimulation wx:if="{{ curCom === 'positionsimulation' }}" bindtoggle="tooggleComponent"></positionsimulation>
    <storage wx:if="{{ curCom === 'storage' }}" bindtoggle="tooggleComponent"></storage>
    <h5door wx:if="{{ curCom === 'h5door' }}" bindtoggle="tooggleComponent"></h5door>
    <httpinjector wx:if="{{ curCom === 'httpinjector' }}" bindtoggle="tooggleComponent"></httpinjector>
    <apimock wx:if="{{ curCom === 'apimock' }}" bindtoggle="tooggleComponent" projectId="{{ projectId }}"></apimock>
</block>
<block wx:else> <cover-image bindtap="tooggleComponent" data-type="debug" class="dokit-entrance" src="//pt-starimg.didistatic.com/static/starimg/img/W8OeOO6Pue1561556055823.png" ></cover-image> </block>
複製代碼

須要注意的部分有如下幾點:

wx:if條件渲染 bindtoggle組件間的通訊 {{curCom}}數據綁定

咱們先來看條件渲染,條件渲染是隻有在wx:if後面的條件成立時纔會視圖層纔會渲染當前的組件,反之則是渲染wx:else部分的組件(注意條件渲染是惰性的,默認初始爲false,不會進行渲染)。 接着咱們看到wx:if中的條件是"{{ curCom!= 'dokit' }}",這是微信小程序WXML語法中的. 數據綁定: 被兩個大括號括住的語句內能夠只放一個變量名或者簡單的運算,內部變量的具體的值是動態的,實際來自與該WXML文件同名的.js文件中的data中同名屬性的值。 查找index.jsdata屬性,能夠看到該變量的值,初始化爲curCom: 'dokit' 所以當組件第一次初始化時,會渲染<block wx:else>內的組件,也就是<cover-image>,經過修改data中的curCom爲debug/appinformation能夠測試一下會數據綁定的效果。能夠看到根據curCom字符串的不一樣,index會展現不一樣的功能窗口。 簡單的展現圖以下:

index結構佈局.png

咱們經過修改curCom的值能夠改變index條件渲染的組件是什麼,而組件本身工做的時候確定要經過用戶的點擊動做來改變curCom的值,這個過程實際上就是組件間發生了通訊。

bindXXX=toggleComponent組件間的通訊

查看以前的index.wxml文件,咱們看到了每一個組件都有一個bindXXX的屬性,且這個屬性的值都是toggleComponent,這其實就是該組件改變curCom值的方式:事件。 組件間的通訊,除了父組件向子組件經過數據綁定傳數據外,還有一種稱爲事件監聽的方式從組件向組件傳遞數據:

  • 事件系統是組件間通訊的主要方式之一。自定義組件能夠觸發任意的事件,引用組件的頁面能夠監聽這些事件;事件是視圖層到邏輯層的通信方式, 能夠將用戶的行爲反饋到邏輯層進行處理。
  • 事件能夠綁定在組件上,當達到觸發事件,就會執行邏輯層中對應的事件處理函數,事件對象能夠攜帶額外信息,如 id, dataset, touches。
  • 監聽自定義組件事件的方法與監聽基礎組件事件的方法徹底一致。

使用事件來實現組件通訊是經過如下的方式:

1.組件進行事件的監聽 2. 組件進行事件的觸發

先來看父組件對子組件的事件是如何監聽的: 在index組件中,爲子組件添加bind屬性,具體語法爲<組件名 bind事件名="事件處理函數"></組件名>

<debug bindtoggle="toggleComponent"></debug>
複製代碼

而後在.js邏輯層添加事件處理函數,當父組件接收到子組件傳遞來的事件後應該執行這個方法來處理。

methods: {
      toggleComponent(e) {
        const componentType = e.currentTarget.dataset.type || e.detail.componentType
          this.setData({
            curCom: componentType
          })
      }
  }
複製代碼

咱們先將這個處理函數的閱讀放在後面,先看子組件的觸發事件方式: 自定義組件觸發事件時,須要使用 triggerEvent 方法,指定事件名、detail對象和事件選項。咱們先隨便找一個功能組件,看看裏面指定事件名爲toggle的方法,以debug組件爲例:

onGoBack () {
   this.triggerEvent('toggle', { componentType: 'dokit'})
   }
複製代碼

在這個方法中,第一個參數是觸發了名爲toggle的事件,第二個參數是構建了一個detail對象:屬性爲componentType,值爲dokit字符串。 看完了子組件觸發事件的函數,咱們能夠回來看父組件是如何響應處理這個事件的了:

  1. 響應函數的參數爲e,event,是包括了子組件傳遞的信息的對象。
  2. 在函數內定義了個變量componentType,賦值爲從e中獲取到的detail對象的componentType值,並調用了組件的setData方法,將該變量的值傳遞給視圖層,且修改index組件中data相應的屬性。

能夠注意,響應函數中不止是componentType = e.detail.componentType而是e.currentTarget.dataset.type || e.detail.componentType,而||運算符前一個值的出處是cover-image

<cover-image
        bindtap="tooggleComponent"
        data-type="debug"
        class="dokit-entrance"
        src="//pt-starimg.didistatic.com/static/starimg/img/W8OeOO6Pue1561556055823.png"
    ></cover-image> 
複製代碼

在這個組件裏監聽的事件不是toggle,而是tap,這是由用戶點擊來觸發的事件,此時傳遞的信息不是detail對象,而是dataset中屬性爲type的值。在此簡要的介紹一下datasetcurrentTarget

  1. currentTarget是事件綁定的當前組件,有兩個屬性:id和dataset。
  2. dataset是當前組件上由data-開頭的自定義屬性組成的集合,在事件中能夠獲取這些自定義的節點數據,用於事件的邏輯處理。
  3. 在 WXML 中,dataset自定義數據以 data- 開頭data-elementType ,最終會在js中呈現爲 event.currentTarget.dataset.elementtype

更詳細的信息請參考小程序官方文檔。

至此,咱們已經明白了index組件中數據層的curCom是經過事件的方式來響應各類事件,如toggletap,進行修改的。但還有一個問題:onGoBack函數雖然觸發了toggle事件,但這個函數又是在哪裏,何時調用的呢?

進一步觀察組件通訊過程

咱們如今已經知道了,邏輯層的方法是在視圖層.wxml文件中經過事件監聽/響應的方式調用的。那麼咱們就搜索一下,onGoBack函數是在哪被調用的。 很快,咱們就能在各個組件裏都找到這樣一個語句,依然以debug組件爲例:

<back bindreturn="onGoBack"></back>
複製代碼

與上一部分bindtoggle="toggleComponent"的工做方式是相同的:debug組件響應子組件back的名爲return的事件,並經過onGoBack函數來處理。 再以此類推,尋找return事件的通訊過程: back.js與back.wxml相關代碼以下:

methods: {
    onbackDokitEntry () {
      this.triggerEvent('return')
    }
  }

<cover-image
    bindtap="onbackDokitEntry"
    data-type="debug"
    class="dokit-back"
    src="//pt-starimg.didistatic.com/static/starimg/img/W8OeOO6Pue1561556055823.png"
    style="top: {{ top }}"
></cover-image>
複製代碼

能夠看到back組件觸發return事件的方式與index組件內cover-image類似,都是bindtap+data-type的方式,再也不贅述。 最後以一張圖來梳理一下這個通訊過程:

總結

到目前爲止,咱們熟悉了Dokit小程序端的總體目錄結構,並閱讀了入口組件——index組件的源代碼。咱們瞭解了自定義組件是如何通訊的,子組件如何利用事件系統來向父組件傳值,父組件是如何響應子組件的。 本次閱讀的代碼量並很少,但咱們瞭解了小程序的一些特點功能如條件渲染、數據綁定、事件系統,爲咱們繼續深刻閱讀源代碼打下了簡單的小程序基礎。

做者信息

做者:亦莊亦諧

原文連接:juejin.cn/post/694807…

來源:掘金

相關文章
相關標籤/搜索