1. 程式人生 > >小程式踩坑日誌(三)----Labrador

小程式踩坑日誌(三)----Labrador

小程式模組化開發框架—–Labrador

之前一直用的微信開發者工具去直接修改程式碼,倒不是說這樣不行,就是不太友好,目錄結構混亂,邏輯不清晰,身為開發者,我有時候都會混淆一些東西,更何況團隊開發,

所以不建議使用微信開發工具去直接修改程式碼,今天在網上看見一個Labrador框架,所以準備研究一下,正式學習之前需要具備一些知識 redux,

Labrador的優勢

  • 支援微信開發工具支援海量npm包
  • 支援es6語法,使用async/await有效避免回撥地獄
  • 對小程式框架二次封裝,實現元件的重用和巢狀
  • 可繼承redux使用redux資料流控制,讓專案邏輯清晰可維護
  • 自動化測試,非常容易編寫單元測試指令碼,不經任何額外配置即可自動化測試
  • Flow.js強型別檢查,編寫更加安全穩定的程式碼
  • 使用Editor Config及ESLint標準化程式碼風格,方便團隊協作
  • 強力壓縮程式碼,儘可能減小程式體積,讓你在1M的限制內做更多的事

環境搭建

首先系統中需要nodejs和npm,然後全域性安裝Labrador-cli

npm install -g labrador-cli

初始化專案

labrador create demo   //新建一個專案
cd demo                //進入demo

開發流程

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

常用命令

labrador create <name>   //建立專案

labrador build 【opation】 //構建當前專案

labrador watch 【opation】  //編輯當前專案並檢測檔案改動

labrador generate 【opation】 <type> <name>
                            //建立新組建,頁面,redux saga

+ labrador generate page home/home //建立資料夾和新的頁面
+ labrador generate component home //建立home元件
+ labrador generate redux home //建立redux檔案 + labrador generate saga home //建立saga檔案

wxml中支援import和include,但僅時檢視模板中可用,並非元件可重用,

wxml其實基於可重用元件,但不允許自定義元件

重要的是,只有真正用到的js檔案才被labrador命令加入到專案目錄中。這樣一個小小的改進象徵著我們的小程式可以便捷呼叫NPM倉庫中海量的擴充套件庫!

原始碼中const _ = require('lodash'); 被編譯為 var _ = require('./npm/lodash/lodash.js');

commonents資料夾中存放公用的元件

在 src/pages/index/index.less 中加入程式碼 @import ‘list’ 即可呼叫list元件的樣式,如果在src/components/list中找不到list.less,那麼編譯命令將在NPM包中尋找 node_modules/list/index.less 。

在 src/pages/index/index.xml 中加入程式碼 即可呼叫list元件的模板檔案,component 是Labrador自定義的元件,編譯後對應生成 import 和 template。如果在src/components/list中找不到list.xml,那麼編譯命令將在NPM包中尋找 node_modules/list/index.xml

頁面(pages)也是元件

預設首頁的示例程式碼

index.js

import wx, { Component } from 'labrador';
import List from '../../components/list/list';
import Title from '../../components/title/title';
import Counter from '../../components/counter/counter';

export default class Index extends wx.Component {
  state = {
    userInfo: {},
    mottoTitle: 'Hello World',
    count: 0
  };

  children() {
    return {
      list: {
        component: List
      },
      motto: {
        component: Title,
        props: {
          text: this.state.mottoTitle
        }
      },
      counter: {
        component: Counter,
        props: {
          count: this.state.count,
          onChange: this.handleCountChange
        }
      }
    };
  }

  handleCountChange(count) {
    this.setState({ count });
  }

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

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

  onReady() {
    this.setState('mottoTitle', 'Labrador');
  }
}

js中export default會匯出一個預設的類,不可手動呼叫Page(),因為在編譯之後pages目錄下所有的js全會自動呼叫Page()方法宣告頁面。

children()方法

children()方法返回該元件依賴,包含的其他自定義元件,

以上的程式碼中包含了三個自定義元件list ,title,counter

children()方法包含兩個屬性,component屬性定義了元件類,props屬性定義了父元件向子元件傳遞的props屬性物件,

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

注意所有的元件生命週期都支援async,但預設的是普通函式,如果函式內沒有非同步操作,建議採用普通函式,async函式會有一定的效能開銷,可能無法順暢的執行

components和pages兩個目錄的區別在於,components中存放的元件能夠被智慧載入,重用,pages目錄中的元件在編譯時加上pages()呼叫,所以pages目錄中的元件不能被重複呼叫,也就是說不可被其他元件呼叫,否則會報錯,

佈局index.xml

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

以上這段程式碼中使用了labrador提供的 標籤,此標籤的作用是匯入一個自定義元件的佈局檔案。標籤有兩個屬性,分別是key(必須)和name(可選,預設是key的值)。key與js邏輯程式碼中的元件key對應,name是 元件的目錄名。

key用來繫結元件js邏輯物件的children中對應的資料,name用於在src/components和node_moudles目錄中尋找子元件模板。

labrador支援多層元件巢狀

自定義元件列表

邏輯 src/components/list/list.js

import wx, { Component } from 'labrador';
import Title from '../title/title';
import Item from '../item/item';
import { sleep } from '../../utils/util';

export default class List extends Component {

  constructor(props){
    super(props);
    this.state = {
      items: [
        { id:1, title: 'Labrador' },
        { id:2, title: 'Alaska' }
      ]
    };
  }

  children (){
    return {
      title:{
        component: Title,
        props: { text: 'The List Title' }
      },
      listItems: this.state.items.map((item) => {
        return {
          component: Item,
          key: item.id,
          props: {
            item: item,
            title: item.title,
            isNew: item.isNew,
            onChange: (title) => { this.handleChange(item, title) }
          }
        };
      })
    };
  }

  async onLoad() {
    await sleep(1000);
    this.setState({
      items: [{ id:3, title: 'Collie', isNew: true }].concat(this.data.items)
    });
  }

  handleChange(item, title) {
    let items = this.state.items.map((i) => {
      if(item.id == i.id){
        return Object.assign({},i,{ title });
      }
      return i;
    });
    this.setState({ items });
  }
}

以上程式碼中children()返回的listItem子元件定義時,是一個元件陣列,陣列的每一項都是一個子元件的定義,並且需要每一項的key屬性,key屬性將用於模板渲染效能優化,建議將唯一且不宜變化的值設為子元件的key