微信小程序-組件化開發(上)

小程序對組件化的「支持」狀況小程序對組件化的「支持」狀況:css

微信小程序(如下簡稱「小程序」,版本)雖然默認定義了不少有用的組件,可是在開發小程序過程當中,每每須要自定義業務組件。
而小程序開發者文檔中卻未對自定義組件給出很好的解決方案或示例。

猜其緣由可能有兩方面:web

  1. 從小程序開放的API來看,它去除了DOM和BOM,視圖與數據層交互採用簡單的單向數據綁定和事件綁的形式。可能其初衷是想下降開發難度和學習門檻,儘可能減小概念。
  2. 小程序推出時間不到一年,這些功能可能還在完善中。

自定義組件的難點

微信的組件化,整體而言,目標就是把具備特定功能和樣式的wxml、wxss、js(可選)文件抽取出來,以便不一樣頁面之間進行復用。
咱們從實現上來考慮是否可行:json

  • wxss支持文件之間的引用,採用命名隔離的話應該能夠支持組件化的需求。即把不一樣組件拆成不一樣的wxss,經過一致的命名與組件的試圖、邏輯對應,同時組件樣式選擇器都掛載在跟樣式下。使用時記得引用該wxss就好。固然預編譯語言中所使用的變量、函數什麼的就不要想了~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// tab component
-
|- tab.wxml
|- tab.js
|- tab.wxss 

// tab.wxss
.tab {
    ...
}
.tab .itme {
    ...
}
...
  • wxml也支持引用,兩種方式:template和include。區別在於做用域。include至關於把代碼拷貝到當前位置,與頁面共享做用域,而import擁有本身的獨立做用於,通常須要傳入對應的參數。這麼看彷佛template更適合,但是template的事件綁定卻還是和父頁面共享做用域,也就是說數據在template獨立做用域中,事件綁定在頁面內做用域,二者之間的相互引用就會變得至關尷尬,還不如include順暢。
  • 小程序支持ES6,因此咱們能夠用ES6的模塊管理方式來引入對應的js文件。
  • 由於json是針對於頁面進行的配置,組件關心的是局部樣式和邏輯,因此組件化的時候咱們並不須要它。

由於咱們採用了include的方式共享了做用域,在簡單頁面的狀況這種方式也不會出現什麼問題,若是變量名或事件名被佔用的時候換一個就行了。
可是在頁面引用多個組件的狀況下如何保證它們之間不產生衝突?你可能想到了用老辦法命名隔離,組件內部變量和事件添加組件前綴用來和其它組件區分。
OK,在組件名不重複的狀況下這是可行的。可是若是一個組件要同時觸發自身內部事件和父頁面事件就不是這麼簡單了。
因此咱們須要解決的一個關鍵問題是:組件如何隔離做用域,並暴露屬性或接口(函數)給頁面或其它組件?小程序

組件化解決方案

第三方實現

咱們在探索組件化實現方式時,有一個第三方模塊wepy脫穎而出。star數量超過了1k,文檔清晰簡約。
看看它的主要功能:微信小程序

  1. 將小程序開發模式轉爲MVVM方式
  2. 支持類Vue.js 2.x風格的組件開發,包括單文件組件,支持scss、pug等。
  3. 支持加載外部NPM包
  4. 使用babel編譯,支持ES6/ES7特性

MVVM多用於web單頁應用,而小程序明顯不是單頁應用,並且也不支持雙數據綁定,轉爲MVVM方式更多隻是習慣上的喜愛,談不上什麼優勢。
小程序也支持ES6特性(之前也支持ES7,不知道爲何新版本取消了),用ES6特性能夠完成外部NPM包引用。微信

因此最吸引人的功能就是第二點:支持組件化。babel

拿到官方給的示例wepy-wechat-demo編譯後對比源碼和編譯後的代碼來探究其實現組件化的思路。xss

整個項目很是清晰簡單,咱們以index頁面調用tab組件爲例進行分析。函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src目錄
-
|- components
 - tab.wpy
 ...
|- pages
 - index.wpy
 ...
 
// dist目錄
- dist
|- components
 - tab.wxss
 - tab.js
|- pages 
 - index.js
 - index.json
 - index.wxml
 - index.wxss

js文件用ES6編寫,經過babel轉成ES5形式,看起來比較費勁,不過幸虧咱們暫時也不須要分析它。打開index.wxss和tab.wxss能夠看到組件樣式的編寫和引用方式如咱們所料,經過微信的@import方式引入。工具

1
2
3
4
5
6
7
8
9
10
11
12
// dist/components/tab.wxss
.tab {
    ...
}
.tab .item {
   ... 
}
...

// dist/pages/index.wxss
@import "./../components/tab.wxss";
...

很奇怪,在編譯好的components文件夾中只能看到組件命名的js和wxss文件,wxml文件消失了~
因此先來看看index.wxml中怎麼體現的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// dist/pages/index.wxml
<view class="tab">
    <view class="tab_item tab_message{{$tab$active == 0 ? ' active' : ''}}" bindtap="$tab$change" data-wepy-params-a="0">
        <image class="icon" src="../images/message{{$tab$active == 0 ? '_active' : ''}}.png"/>
        <text class="title">微信</text>
    </view>
    ...
</view>

// src/components/tab.wxml
<template>
    <view class="tab">
        <view class="tab_item tab_message{{active == 0 ? ' active' : ''}}" @tap="change(0)">
            <image class="icon" src="../images/message{{active == 0 ? '_active' : ''}}.png"></image>
            <text class="title">微信</text>
        </view>
        ...
    </view>
</template>

這段編譯後的代碼和tab.wxml源文件基本一致,發生改變的是數據綁定和事件綁定的地方,進行了重命名。
由此能夠推斷,是經過wepy的編譯工具wepy-cli,把頁面上的組件引用替換成了源碼並經過修改變命名來隔離組件做用域避免衝突。
而這些從新修改的變量和事件如何起做用?
wepy的文檔中提到組件支持回調和事件冒泡、事件下發,要支持這個特性除了按其要求的格式進行編寫以外,還須要在js中引用一個叫wepy的模塊,如

import wepy from 'wepy'

由此能夠推斷,wepy-cli編譯的時候進行了模板替換和變量名(事件名)替換,而後wepy模塊來處理替換後的事件調用以及組件之間的通訊。

若是仔細翻閱文檔會發現其對組件的支持很是接近Vue.js 2.x,好比computed、watcher屬性。行文此處,給做者由衷地點個贊。

那麼這種方式是否就是最理想的組件化方式,或者說這種方式有什麼缺陷呢?

相關文章
相關標籤/搜索