近幾年隨着開源在國內的蓬勃發展,一些高校也開始探索讓開源走進校園,讓同窗們在學生時期就感覺到開源的魅力,這也是高校和國內的頭部互聯網企業共同嘗試的全新教學模式。本專題會記錄這段時間內學生們的學習成果。html
更多專題背景參考:【DoKit&北大專題】緣起前端
【DoKit&北大專題】緣起json
第一篇文章裏咱們將Dokit的模塊引入到了本身的小程序項目中,那麼接下來就是正式的閱讀Dokit的源代碼了。api
DoKit模塊是由多個自定義組件構成的,所以在閱讀源碼以前,咱們須要先簡單的瞭解一下微信小程序自定義組件的基本知識。 微信小程序能夠說是由多個page頁面構成的,而每一個page頁面是由多個組件構成的,其中包括微信的原生組件,也包括了用戶的自定義組件。服務器
自定義組件的構成與Page頁面的構成很是相似,都具備4個文件:js、json、wxml、wxss。微信
HTML
,但沒有HTML的div、p等標籤,取而代之的是微信小程序的各類組件,如view、button等CSS
,但自定義組件內的wxss文件不能使用ID選擇器、屬性選擇器和標籤名選擇器在想要引用組件的page界面或自定義組件的json文件
裏聲明:(自定義組件裏能夠再引用其餘的自定義組件)markdown
{
"usingComponents": {
"dokit": "../../dist/index/index"
}
}
複製代碼
在自定義組件的json文件裏聲明:app
{
"component": true,
"usingComponents": {
"back": "../../components/back/back"
}
}
複製代碼
如圖所示,Dokit的項目主體在dist文件夾
咱們先來了解一下該項目的目錄分佈,有助於咱們對項目有個總體的把控:
assets
——裏面有img文件夾,存儲icon等圖片資源
components
——Dokit最核心的部分,包括了八個自定義組件
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
文件穿插其中。
還記得咱們最初給本身的小程序項目中引入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.js
中data
屬性,能夠看到該變量的值,初始化爲curCom: 'dokit'
所以當組件第一次初始化時,會渲染<block wx:else>
內的組件,也就是<cover-image>
,經過修改data中的curCom
爲debug/appinformation能夠測試一下會數據綁定的效果。能夠看到根據curCom
字符串的不一樣,index會展現不一樣的功能窗口。 簡單的展現圖以下:
咱們經過修改curCom
的值能夠改變index條件渲染的組件是什麼,而組件本身工做的時候確定要經過用戶的點擊動做來改變curCom
的值,這個過程實際上就是組件間發生了通訊。
查看以前的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
字符串。 看完了子組件觸發事件的函數,咱們能夠回來看父組件是如何響應處理這個事件的了:
能夠注意,響應函數中不止是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
的值。在此簡要的介紹一下dataset
和currentTarget
:
- currentTarget是事件綁定的當前組件,有兩個屬性:id和dataset。
- dataset是當前組件上由data-開頭的自定義屬性組成的集合,在事件中能夠獲取這些自定義的節點數據,用於事件的邏輯處理。
- 在 WXML 中,dataset自定義數據以 data- 開頭data-elementType ,最終會在js中呈現爲 event.currentTarget.dataset.elementtype
更詳細的信息請參考小程序官方文檔。
至此,咱們已經明白了index組件中數據層的curCom
是經過事件的方式來響應各類事件,如toggle
或tap
,進行修改的。但還有一個問題: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組件的源代碼。咱們瞭解了自定義組件是如何通訊的,子組件如何利用事件系統來向父組件傳值,父組件是如何響應子組件的。 本次閱讀的代碼量並很少,但咱們瞭解了小程序的一些特點功能如條件渲染、數據綁定、事件系統,爲咱們繼續深刻閱讀源代碼打下了簡單的小程序基礎。
做者:亦莊亦諧
來源:掘金