使用Labrador 0.3構建ES6/ES7標準模組化微信小程式

脈衝雲_樑興臣發表於2016-10-09

Labrador 是一個專為微信小程式開發的模組化的前端開發框架

微信小程式開發三宗罪和解決方案一文中我向大家闡述了微信小程式開發的三個弊端,並提供了Labrador框架來解決這些弊端。

在上一個版本的Labrador中,元件重用部分功能不完善,今天Labrador釋出了0.3版本,相對上一個版本,提供了更強大的元件化功能,並更改了一些模組介面。

下面是Labrador 0.3.x版本的入門手冊,如果你已經基於老版本Labrador構建了專案,請參照下面的說明對應升級專案,並升級一下全域性的 labrador-cli 庫到0.3版本。


QQ交流群 282140496


特性

  • 使用Labrador框架可以使微信開發者工具支援載入海量NPM包

  • 支援ES6/ES7標準程式碼,使用async/await能夠有效避免回撥地獄

  • 元件重用,對微信小程式框架進行了二次封裝,實現了元件重用和巢狀

  • 使用Editor Config及ESLint標準化程式碼風格,方便團隊協作

安裝

npm install -g labrador-cli

初始化專案

mkdir demo
cd demo
npm init
labrador init

專案目錄結構

demo                 # 專案根目錄
├── .babelrc         # babel配置檔案
├── .editorconfig    # Editor Config
├── .eslintignore    # ESLint 忽略配置
├── .eslintrc        # ESLint 語法檢查配置
├── package.json
├── dist/            # 目標目錄
├── node_modules/
└── src/             # 原始碼目錄
    ├── app.js
    ├── app.json
    ├── app.less
    ├── components/  # 通用元件目錄
    ├── pages/       # 頁面目錄
    └── utils/

注意 dist目錄中的所有檔案是由labrador命令生成,請勿直接修改

配置開發工具

專案初始化後使用WebStorm或Sublime等你習慣的IDE開啟專案根目錄。然後開啟 微信web開發者工具 新建專案,本地開發目錄選擇 dist 目標目錄。

開發流程

在WebStorm或Sublime等IDE中編輯 src 目錄下的原始碼,然後在專案根目錄中執行labrador build 命令構建專案,然後在 微信web開發者工具 的除錯介面中點選左側選單的 重啟 按鈕即可檢視效果。

我們在開發中, 微信web開發者工具 僅僅用來做除錯和預覽,不要在 微信web開發者工具 的編輯介面修改程式碼。

微信web開發者工具 會偶爾出錯,表現為點選 重啟 按鈕沒有反應,除錯控制檯輸出大量的無法require檔案的錯誤,編輯 介面中程式碼檔案不顯示。這是因為 labrador build 命令會更新整個 dist 目錄,而 微信web開發者工具 在監測程式碼改變時會出現異常,遇到這種情況只需要關掉 微信web開發者工具 再啟動即可。

我們還可以使用 labrador watch 命令來監控 src 目錄下的程式碼,當發生改變後自動構建,不用每一次編輯程式碼後手動執行 labrador build

所以最佳的姿勢是:

  1. 在專案中執行 labrador watch

  2. 在WebStorm中編碼,儲存

  3. 切換到 微信web開發者工具 中除錯、預覽

  4. 再回到WebStorm中編碼

labrador 庫

labrador 庫對全域性的 wx 變數進行了封裝,將大部分 wx 物件中的方法進行了Promise支援, 除了以 on* 開頭或以 *Sync 結尾的方法。在如下程式碼中使用 labrador 庫。

import wx from `labrador`;

我們建議不要再使用 wx.getStorageSync() 等同步阻塞方法,而在 async 函式中使用 await wx.getStorage() 非同步非阻塞方法提高效能,除非特殊情況。

app.js

src/app.js 示例程式碼如下:

import wx from `labrador`;
import { sleep } from `./utils/util`;

export default class {
  globalData = {
    userInfo: null
  };

  async onLaunch() {
    //呼叫API從本地快取中獲取資料
    let logs = await wx.getStorage({ key: `logs` }) || [];
    logs.unshift(Date.now());
    await wx.setStorage({ key: `logs`, data: logs });
    this.timer();
  }

  async timer() {
    while (true) {
      console.log(`hello`);
      await sleep(10000);
    }
  }

  async getUserInfo() {
    if (this.globalData.userInfo) {
      return this.globalData.userInfo;
    }
    await wx.login();
    let res = await wx.getUserInfo();
    this.globalData.userInfo = res.userInfo;
    return res.userInfo;
  }
}

程式碼中全部使用ES6/ES7標準語法。程式碼不必宣告 use strict ,因為在編譯時,所有程式碼都會強制使用嚴格模式。

程式碼中並未呼叫全域性的 App() 方法,而是使用 export 語法預設匯出了一個類,在編譯後,Labrador會自動增加 App() 方法呼叫,所有請勿手動呼叫 App() 方法。

自定義元件

Labrador的自定義元件,是基於微信小程式框架的元件之上,進一步自定義組合,擁有邏輯處理和樣式。這樣做的目的請參見 微信小程式開發三宗罪和解決方案

專案中通用自定義元件存放在 src/compontents 目錄,一個元件一般由三個檔案組成,*.js*.xml*.less 分別對應微信小程式框架的 jswxmlwxss 檔案。在Labardor專案原始碼中,我們特意採用了 xmlless 字尾以示區別。

自定義元件示例

下面是一個簡單的自定義元件程式碼例項:

邏輯 src/compontents/title/title.js

import wx from `labrador`;
import randomColor  from `../../utils/random-color`;

export default class Title extends wx.Component {
  data = {
    text: ``,
    color: randomColor()
  };

  handleTap() {
    this.setData({
      color: randomColor()
    });
  }
}

佈局 src/compontents/title/title.js

<view class="text-view">
  <text class="title-text" catchtap="handleTap" style="color:{{color}};">{{text}}</text>
</view>

樣式 src/compontents/title/title.less

.title-text {
  font-weight: bold;
  font-size: 2em;
}

程式碼和微信小程式框架中的page很相似。最大的區別是在js邏輯程式碼中,沒有呼叫全域性的Page()函式宣告頁面,而是用 export 語法匯出了一個預設的類,這個類需要繼承與 labrador.Component 元件基類。

注意 元件中事件響應方法必須以 handle 開頭!例如上文中的 handleTap

頁面

我們要求所有的頁面必須存放在 pages 目錄中,每個頁面的子目錄中的檔案格式和自定義元件一致,只是可以多出一個 *.json 配置檔案。

頁面示例

下面是預設首頁的示例程式碼:

邏輯 src/pages/index/index.js

import wx from `labrador`;
import List from `../../components/list/list`;
import Title from `../../components/title/title`;

export default class Index extends wx.Component {
  data = {
    userInfo: {}
  };
  children = {
    list: new List(),
    motto: new Title({ text: `Hello world` })
  };

  //事件處理函式
  handleViewTap() {
    wx.navigateTo({
      url: `../logs/logs`
    })
  }

  async onLoad() {
    //呼叫應用例項的方法獲取全域性資料
    let userInfo = await wx.app.getUserInfo();
    //更新資料
    this.setData({
      userInfo: userInfo
    });
    this.update();
  }
}

佈局 src/pages/index/index.xml

<view class="container">
  <view bindtap="handleViewTap" class="userinfo">
    <image class="userinfo-avatar" src="{{ userInfo.avatarUrl }}" background-size="cover"/>
    <text class="userinfo-nickname">{{ userInfo.nickName }}</text>
  </view>
  <view class="usermotto">
    <component key="motto" name="title"/>
  </view>
  <component key="list"/>
</view>

樣式

@import `list`;
@import `title`;

.motto-title-text {
  font-size: 3em;
  padding-bottom: 1rem;
}

/* ... */

頁面程式碼的格式和自定義元件的格式一模一樣,我們的思想是 頁面也是元件,頁面和自定義元件的唯一差別是頁面的程式碼存放在 pages 目錄中。

js邏輯程式碼中同樣使用 export 語句匯出了一個預設類,也不能手動呼叫 Page() 方法,因為在編譯後,pages 目錄下的所有js檔案全部會自動呼叫 Page() 方法宣告頁面。

我們看到元件類中,有一個物件屬性 children ,這個屬性定義了該元件依賴、包含的其他自定義元件,在上面的程式碼中頁面包含了兩個自定義元件 listtitle ,這個兩個自定義元件的 key 分別為 listmotto

xml佈局程式碼中,使用了Labrador提供的 <component/> 標籤,此標籤的作用是匯入一個自定義子元件的佈局檔案,標籤有兩個屬性,分別為 key (必選)和 name (可選,預設為key的值)。key 與js邏輯程式碼中的元件 key 對應,name 用來在src/componetsnode_modules 目錄中尋找子元件模板。執行時,key對應的子元件邏輯程式碼類中的 data 將渲染至子元件模板中。

less樣式檔案中,我們使用了兩條 @import 語句載入子元件樣式,這裡的 @import `list` 語句按照LESS的語法,會首先尋找當前目錄 src/pages/index/ 中的 list.less 檔案,如果找不到就會嘗試尋找 src/componetsnode_modules 目錄中的元件樣式。

接下來,我們定義了 .motto-title-text 樣式,這樣做是因為 motto key 代表的title元件的模板中有一個view 屬於 title-text 類,編譯時,Labrador將自動為其增加一個字首 motto- ,所以編譯後這個view所屬的類為 title-text motto-title-text 那麼我們就可以在父元件的樣式程式碼中使用 .motto-title-text 重新定義子元件的樣式。

注意 雖然我們採用了LESS檔案,但是由於微信小程式框架的限制,不能使用LESS的層級選擇及巢狀語法。但是我們可以使用LESS的變數、mixin、函式等功能方便開發。

另外Labrador支援多層元件巢狀,在上述的例項中,index 包含子元件 listtitlelist 包含子元件 title,所以在最終顯示時,index 頁面上回顯示兩個 title 元件。

詳細程式碼請參閱 labrador init 命令生成的示例專案。

總結

頁面也是元件,所有的元件都擁有一樣的生命週期函式onLoad, onReady, onShow, onHide, onUnload 以及setData函式。

componetspages 兩個目錄的區別在於,componets 中存放的元件能夠被智慧載入,pages 目錄中的元件在編譯時自動加上 Page() 呼叫,所以,pages 目錄中的元件不能被其他元件呼叫,如果某個元件需要重用,請存放在 componets 目錄或打包成NPM包。

貢獻者

鄭州脈衝軟體科技有限公司

樑興臣

開源協議

本專案依據MIT開源協議釋出,允許任何組織和個人免費使用。

相關文章