1. 程式人生 > >小程式從入門到快速開發小程式專案

小程式從入門到快速開發小程式專案

作者:譚東

備註:小程式只是突發靈感興趣弄的,並非專業研究小程式,其實小程式API並不多,不復雜,擴充套件無非就是JS了。

然後有目標的進行實踐,也就是要實現個你想要的小程式,這樣邊實踐邊學習才能夠有疑問,才能夠更快的理解和學習小程式開發。所以後續幾天就開始小程式實踐和學習之旅了,期間也遇到了一些問題並且學到了很多基礎知識和解決方案。接下來給大家講解下小程式的開發基本知識和擴充套件知識。

官方文件其實寫的基本很詳細了,我們先從工具開始說起。

1、小程式開發者工具。

下載安裝好後,先要微信掃描登入。然後選擇小程式專案。

新建小程式專案。

選擇新建小程式的專案目錄,AppID沒有註冊的話,可以先點選下面的使用測試號即可,不影響開發。

大致的工具介面如下圖,新版有版本管理。紅色圈起來的為小程式專案的一個頁面包含的元素:

工具用起來很方便、簡單、直接。詳細用法就不說了,主要的功能大概說下。左側是模擬器,可以模擬安卓手機和蘋果手機的效果,因為有些小程式元件在安卓和蘋果上顯示是有區別的,大家可以注意下。圈紅的為小程式一個頁面的基本組成檔案元素:xx.js、xx.wxml、xx.wxss、xx.json。其實就是有JS檔案、HTML檔案(xx.wxml)、CSS樣式檔案(xx.wxss)和配置檔案(xx.json)組成,非常的容易理解。我們就是在使用小程式的元件、控制元件來繪製UI佈局,主要是xx.wxml和xx.wxss檔案。xx.js負責生命週期函式和事件處理,例如:點選事件、資料請求、資料繫結等等邏輯操作。

我們在編寫完後,可以點選工具欄上的預覽按鈕,掃描二維碼在真機上體驗,也可以直接用左側的模擬器時時預覽即可。

看完了工具,我們看下基本開發的要素和需要注意的問題吧,以免新手再次重蹈覆轍。

看下預設的新建後的結構:

app.json是小程式全域性配置檔案,包括了小程式的所有頁面路徑、介面表現、網路超時時間、底部 tab 等。

大致程式碼結構如下:

{
  "pages":[
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"black"
  }
}

pages是配置小程式所有頁面,類似於註冊清單。window是全域性的視窗配置,如顏色、標題等等。當然每個頁面也可以自己單獨配置,就是頁面名稱.json檔案。例如:page.json。不過需要注意的是,單獨頁面配置的json無需寫window這個關鍵字,直接如下程式碼所示:

{
  "backgroundTextStyle": "light",
  "navigationBarBackgroundColor": "#34495e",
  "navigationBarTitleText": "日記",
  "navigationBarTextStyle": "white",
  "enablePullDownRefresh": true,
  "backgroundColor": "#34495e"
}

那麼再看工具配置檔案project.config.json。

通常大家在使用一個工具的時候,都會針對各自喜好做一些個性化配置,例如介面顏色、編譯配置等等,當你換了另外一臺電腦重新安裝工具的時候,你還要重新配置。考慮到這點,小程式開發者工具在每個專案的根目錄都會生成一個 project.config.json,你在工具上做的任何配置都會寫入到這個檔案,當你重新安裝工具或者換電腦工作時,你只要載入同一個專案的程式碼包,開發者工具就自動會幫你恢復到當時你開發專案時的個性化配置,其中會包括編輯器的顏色、程式碼上傳時自動壓縮等等一系列選項。具體詳細配置大家可以看小程式官方文件有詳細介紹。

還有一個app.wxss和app.js。這個app.wxss就是全域性的樣式檔案,也就是css檔案,當然和頁面配置檔案一樣,每個頁面可以單獨寫頁面名稱.wxss。

WXSS 具有 CSS 大部分的特性,小程式在 WXSS 也做了一些擴充和修改。

新增了尺寸單位。在寫 CSS 樣式時,開發者需要考慮到手機裝置的螢幕會有不同的寬度和裝置畫素比,採用一些技巧來換算一些畫素單位。WXSS 在底層支援新的尺寸單位 rpx ,開發者可以免去換算的煩惱,只要交給小程式底層來換算即可,由於換算採用的浮點數運算,所以運算結果會和預期結果有一點點偏差。

提供了全域性的樣式和區域性樣式。和前邊 app.json, page.json 的概念相同,你可以寫一個 app.wxss 作為全域性樣式,會作用於當前小程式的所有頁面,區域性頁面樣式 page.wxss 僅對當前頁面生效。

此外 WXSS 僅支援部分 CSS 選擇器

再來看app.js,很明顯是一個js檔案。負責UI互動、資料繫結更新、網路請求、頁面生命週期等等操作相關的都在這裡。當然每個頁面都有自己單獨的.js檔案,這個app.js可以做一些需要全域性共享和操作的邏輯在裡面。在這裡可以呼叫微信小程式的很多API,也可以自己寫js方法使用。

那麼我們看下一個頁面的組成,基本上就是下圖這些結構元素。有介面、有樣式、有js互動、有配置。

每新增一個頁面都要在app.json裡添加註冊進去。

一個.js檔案裡有生命週期的管理函式,可以在這裡面做相應的操作。

Page({

  /**
   * 頁面的初始資料
   */
  data: {
    
  },

  /**
   * 生命週期函式--監聽頁面載入
   */
  onLoad: function (options) {
    
  },

  /**
   * 生命週期函式--監聽頁面初次渲染完成
   */
  onReady: function () {
    
  },

  /**
   * 生命週期函式--監聽頁面顯示
   */
  onShow: function () {
    
  },

  /**
   * 生命週期函式--監聽頁面隱藏
   */
  onHide: function () {
    
  },

  /**
   * 生命週期函式--監聽頁面解除安裝
   */
  onUnload: function () {
    
  },

  /**
   * 頁面相關事件處理函式--監聽使用者下拉動作
   */
  onPullDownRefresh: function () {
    
  },

  /**
   * 頁面上拉觸底事件的處理函式
   */
  onReachBottom: function () {
    
  },

  /**
   * 使用者點選右上角分享
   */
  onShareAppMessage: function () {
    
  }
})

我們看下最簡單的一個index.wxml頁面,可以當做是Html頁面,只有一個text控制元件,裡面的bindtap就是點選事件的繫結。

<!--index.wxml-->
<view class="container">
  <view class="usermotto">
    <text class="user-motto" bindtap='click'>{{motto}}</text>
  </view>
</view>

那麼這個class就是index.wxss裡的樣式檔案。裡面的{{motto}}就是指向index.js裡的data裡定義的一個變數。小程式都是通過{{..}}兩個大括號包括一個英文名字來進行變數繫結的。這樣我們就可以動態更換裡面的顯示內容了。那麼怎麼更新內容呢?

在js裡使用下面的this.setData方式動態更新重新整理資料:

this.setData({ motto: "名字" })
/**index.wxss**/
.userinfo {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.userinfo-avatar {
  width: 128rpx;
  height: 128rpx;
  margin: 20rpx;
  border-radius: 50%;
}

.userinfo-nickname {
  color: #aaa;
}

.usermotto {
  margin-top: 200px;
}

再看下index.

js檔案。

//index.js
//獲取應用例項
const app = getApp()

Page({
  data: {
    motto: 'Hello World',
  },
  
  //事件處理函式
  click: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
    
})

Page函式是必須要有的,裡面包含data:{  ... },用於放置資料、常量、變數等等。這裡的click:function就是我們定義的點選事件。wx.navigateTo...方法就是小程式的官方API,具體其他API的用法和返回引數是什麼可以看官方API文件,很詳細。

觀察下,上面有個聲明瞭app這個常量。這個就是app.js裡拿到的全域性管理呼叫app.js裡的方法和常量用的。很多需要儲存和全域性讀寫、處理的都可以進行操作以及放置在app.js裡。在 JavaScript 檔案中宣告的變數和函式只在該檔案中有效;不同的檔案中可以宣告相同名字的變數和函式,不會互相影響。通過全域性函式 getApp() 可以獲取全域性的應用例項,如果需要全域性的資料可以在 App() 中設定。

Page({
  data: { // 參與頁面渲染的資料
    logs: []
  },
  onLoad: function () {
    // 頁面渲染後執行
  }
})

小程式的元件和控制元件有很多,可以看做是Html的標籤,對稱方式使用。具體元件特性看官方文件:

為了讓開發者可以很方便的調起微信提供的能力,例如獲取使用者資訊、微信支付等等,小程式提供了很多 API 給開發者,例如:

要獲取使用者的地理位置時,只需要:

wx.getLocation({
  type: 'wgs84',
  success: (res) => {
    var latitude = res.latitude // 經度
    var longitude = res.longitude // 緯度
  }
})

呼叫微信掃一掃能力,只需要:

wx.scanCode({
  success: (res) => {
    console.log(res)
  }
})

需要注意的是:多數 API 的回撥都是非同步,你需要處理好程式碼邏輯的非同步問題。更多API說明和用法,看官方文件。

頁面的生命週期,我之前說過了,比較重要,大家可以看下理解下。

看下邏輯層需要注意的。除了頁面的生命週期,還有頁面的監聽事件。onPullDownRefresh():監聽使用者下拉重新整理事件。

需要在app.json的window選項中或頁面配置中開啟enablePullDownRefresh。
可以通過wx.startPullDownRefresh觸發下拉重新整理,呼叫後觸發下拉重新整理動畫,效果與使用者手動下拉重新整理一致。
當處理完資料重新整理後,wx.stopPullDownRefresh可以停止當前頁面的下拉重新整理。

onReachBottom():監聽使用者上拉觸底事件。

可以在app.json的window選項中或頁面配置中設定觸發距離onReachBottomDistance,預設為50px。
在觸發距離內滑動期間,本事件只會被觸發一次。

onPageScroll(Object):監聽使用者滑動頁面事件。

onShareAppMessage(Object):

監聽使用者點選頁面內轉發按鈕(<button> 元件 open-type="share")或右上角選單“轉發”按鈕的行為,並自定義轉發內容。

注意:只有定義了此事件處理函式,右上角選單才會顯示“轉發”按鈕。

onTabItemTap(Object):點選 tab 時觸發。

Page.prototype.setData(Object data, Function callback):setData 函式用於將資料從邏輯層傳送到檢視層(非同步),同時改變對應的 this.data 的值(同步)。

Object 以 key: value 的形式表示,將 this.data 中的 key 對應的值改變成 value。

其中 key 可以以資料路徑的形式給出,支援改變陣列中的某一項或物件的某個屬性,如 array[2].message,a.b.c.d,並且不需要在 this.data 中預先定義。

注意:

直接修改 this.data 而不呼叫 this.setData 是無法改變頁面的狀態的,還會造成資料不一致。
僅支援設定可 JSON 化的資料。
單次設定的資料不能超過1024kB,請儘量避免一次設定過多的資料。
請不要把 data 中任何一項的 value 設為 undefined ,否則這一項將不被設定並可能遺留一些潛在問題。

接下來看下小程式裡的路由、跳轉。

主要有這幾種方式:

這幾種方式url都可以傳遞引數。

wx.navigateTo:保留當前頁面,跳轉到應用內的某個頁面,使用wx.navigateBack可以返回到原頁面。注意:目前頁面路徑最多隻能十層。

wx.redirectTo(OBJECT):關閉當前頁面,跳轉到應用內的某個頁面。如果你想讓頁面沒有返回按鈕,不能返回的話,就用這個跳轉方式吧。

wx.reLaunch(OBJECT):關閉所有頁面,開啟到應用內的某個頁面。

wx.switchTab(OBJECT):跳轉到 tabBar 頁面,並關閉其他所有非 tabBar 頁面。

wx.navigateBack(OBJECT):關閉當前頁面,返回上一頁面或多級頁面。可通過 getCurrentPages() 獲取當前的頁面棧,決定需要返回幾層。

注意:

1、navigateTo, redirectTo 只能開啟非 tabBar 頁面。
2、switchTab 只能開啟 tabBar 頁面。
3、reLaunch 可以開啟任意頁面。
4、頁面底部的 tabBar 由頁面決定,即只要是定義為 tabBar 的頁面,底部都有 tabBar。
5、呼叫頁面路由帶的引數可以在目標頁面的onLoad中獲取。

再看下模組化。

可以將一些公共的程式碼抽離成為一個單獨的 js 檔案,作為一個模組。模組只有通過 module.exports 或者 exports 才能對外暴露介面。

需要注意的是:

exports 是 module.exports 的一個引用,因此在模組裡邊隨意更改 exports 的指向會造成未知的錯誤。所以更推薦開發者採用 module.exports 來暴露模組介面,除非你已經清晰知道這兩者的關係。小程式目前不支援直接引入 node_modules , 開發者需要使用到 node_modules 時候建議拷貝出相關的程式碼到小程式的目錄中。

// common.js
function sayHello(name) {
  console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {
  console.log(`Goodbye ${name} !`)
}

module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye

​在需要使用這些模組的檔案中,使用 require(path) 將公共程式碼引入:

var common = require('common.js')
Page({
  helloMINA: function() {
    common.sayHello('MINA')
  },
  goodbyeMINA: function() {
    common.sayGoodbye('MINA')
  }
})

注意:require 暫時不支援絕對路徑。

接下來看下小程式的檢視層,也就是wxml和wxss。

框架的檢視層由 WXML 與 WXSS 編寫,由元件來進行展示。將邏輯層的資料反應成檢視,同時將檢視層的事件傳送給邏輯層。

WXML(WeiXin Markup language) 用於描述頁面的結構。

WXS(WeiXin Script) 是小程式的一套指令碼語言,結合 WXML,可以構建出頁面的結構。

WXSS(WeiXin Style Sheet) 用於描述頁面的樣式。

元件(Component)是檢視的基本組成單元。

這裡挑幾個比較重要的來說。首先是列表渲染,就是我們想實現一個List列表展示的時候,要進行List資料繫結,item資料繫結、可能還會涉及到模板和資料傳遞等等。

列表渲染:

<!--wxml-->
<view wx:for="{{array}}"> {{item}} </view>
// page.js
Page({
  data: {
    array: [1, 2, 3, 4, 5]
  }
})

在元件上使用 wx:for 控制屬性繫結一個數組,即可使用陣列中各項的資料重複渲染該元件。預設陣列的當前項的下標變數名預設為 index,陣列當前項的變數名預設為 item。

<view wx:for="{{array}}">
  {{index}}: {{item.message}}
</view>

使用 wx:for-item 可以指定陣列當前元素的變數名,

使用 wx:for-index 可以指定陣列當前下標的變數名:

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>

wx:for 也可以巢狀。類似 block wx:if,也可以將 wx:for 用在<block/>標籤上,以渲染一個包含多節點的結構塊。例如:

<block wx:for="{{[1, 2, 3]}}">
  <view> {{index}}: </view>
  <view> {{item}} </view>
</block>

如果列表中專案的位置會動態改變或者有新的專案新增到列表中,並且希望列表中的專案保持自己的特徵和狀態(如 <input/> 中的輸入內容,<switch/> 的選中狀態),需要使用 wx:key 來指定列表中專案的唯一的識別符號。

wx:key 的值以兩種形式提供:

字串,代表在 for 迴圈的 array 中 item 的某個 property,該 property 的值需要是列表中唯一的字串或數字,且不能動態改變。
保留關鍵字 *this 代表在 for 迴圈中的 item 本身,這種表示需要 item 本身是一個唯一的字串或者數字,如:
當資料改變觸發渲染層重新渲染的時候,會校正帶有 key 的元件,框架會確保他們被重新排序,而不是重新建立,以確保使元件保持自身的狀態,並且提高列表渲染時的效率。

如不提供 wx:key,會報一個 warning, 如果明確知道該列表是靜態,或者不必關注其順序,可以選擇忽略。

條件渲染:

<!--wxml-->
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> MINA </view>
// page.js
Page({
  data: {
    view: 'MINA'
  }
})

在框架中,使用 wx:if="{{condition}}" 來判斷是否需要渲染該程式碼塊。

因為 wx:if 之中的模板也可能包含資料繫結,所以當 wx:if 的條件值切換時,框架有一個區域性渲染的過程,因為它會確保條件塊在切換時銷燬或重新渲染。同時 wx:if 也是惰性的,如果在初始渲染條件為 false,框架什麼也不做,在條件第一次變成真的時候才開始區域性渲染。

相比之下,hidden 就簡單的多,元件始終會被渲染,只是簡單的控制顯示與隱藏。

一般來說,wx:if 有更高的切換消耗而 hidden 有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用 hidden 更好,如果在執行時條件不大可能改變則 wx:if 較好。

還可能會涉及到模板template,可以在模板中定義程式碼片段,然後在不同的地方呼叫。

使用 name 屬性,作為模板的名字。然後在<template/>內定義程式碼片段,如:

<!--
  index: int
  msg: string
  time: string
-->
<template name="msgItem">
  <view>
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template>

使用 is 屬性,宣告需要的使用的模板,然後將模板所需要的 data 傳入,如:

<template is="msgItem" data="{{...item}}"/>
Page({
  data: {
    item: {
      index: 0,
      msg: 'this is a template',
      time: '2016-09-15'
    }
  }
})

is 屬性可以使用 Mustache 語法,來動態決定具體需要渲染哪個模板:

<template name="odd">
  <view> odd </view>
</template>
<template name="even">
  <view> even </view>
</template>

<block wx:for="{{[1, 2, 3, 4, 5]}}">
	<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>

模板擁有自己的作用域,只能使用 data 傳入的資料以及模版定義檔案中定義的 <wxs /> 模組。

另外,target(觸發事件的源元件)和currentTarget(事件繫結的當前元件)也比較重要,大家可以自行看例子和文件學習。

dataset:在元件中可以定義資料,這些資料將會通過事件傳遞給 SERVICE。 書寫方式: 以data-開頭,多個單詞由連字元-連結,不能有大寫(大寫會自動轉成小寫)如data-element-type,最終在 event.currentTarget.dataset 中會將連字元轉成駝峰elementType。

<view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>
Page({
  bindViewTap:function(event){
    event.currentTarget.dataset.alphaBeta === 1 // - 會轉為駝峰寫法
    event.currentTarget.dataset.alphabeta === 2 // 大寫會轉為小寫
  }
})

小程式的引用,如引用外部css檔案、引入js檔案、引入wxml模板檔案等等。

WXML 提供兩種檔案引用方式import和include。

import可以在該檔案中使用目標檔案定義的template,如:在 item.wxml 中定義了一個叫item的template:

<!-- item.wxml -->
<template name="item">
  <text>{{text}}</text>
</template>

在 index.wxml 中引用了 item.wxml,就可以使用item模板:

<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>

import 有作用域的概念,即只會 import 目標檔案中定義的 template,而不會 import 目標檔案 import 的 template。

include 可以將目標檔案除了 <template/> <wxs/> 外的整個程式碼引入,相當於是拷貝到 include 位置,如:

<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>

再講一個wxs檔案,不太常用。WXS(WeiXin Script)是小程式的一套指令碼語言,結合 WXML,可以構建出頁面的結構。

注意:
1、wxs 不依賴於執行時的基礎庫版本,可以在所有版本的小程式中執行。
2、wxs 與 javascript 是不同的語言,有自己的語法,並不和 javascript 一致。
3、wxs 的執行環境和其他 javascript 程式碼是隔離的,wxs 中不能呼叫其他 javascript 檔案中定義的函式,也不能呼叫小程式提供的API。
4、wxs 函式不能作為元件的事件回撥。
5、由於執行環境的差異,在 iOS 裝置上小程式內的 wxs 會比 javascript 程式碼快 2 ~ 20 倍。在 android 裝置上二者執行效率無差異。
以下是一些使用 WXS 的簡單示例。

頁面渲染:

<!--wxml-->
<wxs module="m1">
var msg = "hello world";

module.exports.message = msg;
</wxs>

<view> {{m1.message}} </view>

頁面輸出:

hello world

資料處理:

// page.js
Page({
  data: {
    array: [1, 2, 3, 4, 5, 1, 2, 3, 4]
  }
})
<!--wxml-->
<!-- 下面的 getMax 函式,接受一個數組,且返回陣列中最大的元素的值 -->
<wxs module="m1">
var getMax = function(array) {
  var max = undefined;
  for (var i = 0; i < array.length; ++i) {
    max = max === undefined ? 
      array[i] : 
      (max >= array[i] ? max : array[i]);
  }
  return max;
}

module.exports.getMax = getMax;
</wxs>

<!-- 呼叫 wxs 裡面的 getMax 函式,引數為 page.js 裡面的 array -->
<view> {{m1.getMax(array)}} </view>

頁面會輸出5。

WXS 程式碼可以編寫在 wxml 檔案中的 <wxs> 標籤內,或以 .wxs 為字尾名的檔案內。

每一個 .wxs 檔案和 <wxs> 標籤都是一個單獨的模組。每個模組都有自己獨立的作用域。即在一個模組裡面定義的變數與函式,預設為私有的,對其他模組不可見。一個模組要想對外暴露其內部的私有變數與函式,只能通過 module.exports 實現。

可以直接建立 .wxs 檔案,在其中直接編寫 WXS 指令碼。

var foo = "'hello world' from comm.wxs";
var bar = function(d) {
  return d;
}
module.exports = {
  foo: foo,
  bar: bar
};

在.wxs檔案裡面編寫了 WXS 程式碼。該 .wxs 檔案可以被其他的 .wxs 檔案 或 WXML 中的 <wxs> 標籤引用。

每個 wxs 模組均有一個內建的 module 物件。exports:通過該屬性,可以對外共享本模組的私有變數與函式。

// /pages/tools.wxs

var foo = "'hello world' from tools.wxs";
var bar = function (d) {
  return d;
}
module.exports = {
  FOO: foo,
  bar: bar,
};
module.exports.msg = "some msg";
<!-- page/index/index.wxml -->

<wxs src="./../tools.wxs" module="tools" />
<view> {{tools.msg}} </view>
<view> {{tools.bar(tools.FOO)}} </view>

頁面輸出:

some msg
'hello world' from tools.wxs

在.wxs模組中引用其他 wxs 檔案模組,可以使用 require 函式。

引用的時候,要注意如下幾點:

1、只能引用 .wxs 檔案模組,且必須使用相對路徑。
2、wxs 模組均為單例,wxs 模組在第一次被引用時,會自動初始化為單例物件。多個頁面,多個地方,多次引用,使用的都是同一個 wxs 模組物件。
3、如果一個 wxs 模組在定義之後,一直沒有被引用,則該模組不會被解析與執行。

module 屬性是當前 <wxs> 標籤的模組名。在單個 wxml 檔案內,建議其值唯一。有重複模組名則按照先後順序覆蓋(後者覆蓋前者)。不同檔案之間的 wxs 模組名不會相互覆蓋。module 屬性值的命名必須符合下面兩個規則:

1、首字元必須是:字母(a-zA-Z),下劃線(_)。
2、剩餘字元可以是:字母(a-zA-Z),下劃線(_), 數字(0-9)。

src 屬性可以用來引用其他的 wxs 檔案模組。引用的時候,要注意如下幾點:

1、只能引用 .wxs 檔案模組,且必須使用相對路徑。
2、wxs 模組均為單例,wxs 模組在第一次被引用時,會自動初始化為單例物件。多個頁面,多個地方,多次引用,使用的都是同一個 wxs 模組物件。
3、如果一個 wxs 模組在定義之後,一直沒有被引用,則該模組不會被解析與執行。

注意:
1、<wxs> 模組只能在定義模組的 WXML 檔案中被訪問到。使用 <include> 或 <import> 時,<wxs> 模組不會被引入到對應的 WXML 檔案中。
2、<template> 標籤中,只能使用定義該 <template> 的 WXML 檔案中定義的 <wxs> 模組。

再看下官方給出的小程式效能優化建議。

setData 是小程式開發中使用最頻繁的介面,也是最容易引發效能問題的介面。在介紹常見的錯誤用法前,先簡單介紹一下 setData 背後的工作原理。

小程式的檢視層目前使用 WebView 作為渲染載體,而邏輯層是由獨立的 JavascriptCore 作為執行環境。在架構上,WebView 和 JavascriptCore 都是獨立的模組,並不具備資料直接共享的通道。當前,檢視層和邏輯層的資料傳輸,實際上通過兩邊提供的 evaluateJavascript 所實現。即使用者傳輸的資料,需要將其轉換為字串形式傳遞,同時把轉換後的資料內容拼接成一份 JS 指令碼,再通過執行 JS 指令碼的形式傳遞到兩邊獨立環境。而 evaluateJavascript 的執行會受很多方面的影響,資料到達檢視層並不是實時的。

常見的 setData 操作錯誤:
1. 頻繁的去 setData。

在我們分析過的一些案例裡,部分小程式會非常頻繁(毫秒級)的去setData,其導致了兩個後果:Android 下使用者在滑動時會感覺到卡頓,操作反饋延遲嚴重,因為 JS 執行緒一直在編譯執行渲染,未能及時將使用者操作事件傳遞到邏輯層,邏輯層亦無法及時將操作處理結果及時傳遞到檢視層;
渲染有出現延時,由於 WebView 的 JS 執行緒一直處於忙碌狀態,邏輯層到頁面層的通訊耗時上升,檢視層收到的資料訊息時距離發出時間已經過去了幾百毫秒,渲染的結果並不實時;
2. 每次 setData 都傳遞大量新資料。

由setData的底層實現可知,我們的資料傳輸實際是一次 evaluateJavascript 指令碼過程,當資料量過大時會增加指令碼的編譯執行時間,佔用 WebView JS 執行緒,

3. 後臺態頁面進行 setData。

當頁面進入後臺態(使用者不可見),不應該繼續去進行setData,後臺態頁面的渲染使用者是無法感受的,另外後臺態頁面去setData也會搶佔前臺頁面的執行。

圖片資源:
目前圖片資源的主要效能問題在於大圖片和長列表圖片上,這兩種情況都有可能導致 iOS 客戶端記憶體佔用上升,從而觸發系統回收小程式頁面。

圖片對記憶體的影響:
在 iOS 上,小程式的頁面是由多個 WKWebView 組成的,在系統記憶體緊張時,會回收掉一部分 WKWebView。從過去我們分析的案例來看,大圖片和長列表圖片的使用會引起 WKWebView 的回收。

圖片對頁面切換的影響:
除了記憶體問題外,大圖片也會造成頁面切換的卡頓。我們分析過的案例中,有一部分小程式會在頁面中引用大圖片,在頁面後退切換中會出現掉幀卡頓的情況。當前我們建議開發者儘量減少使用大圖片資源。

程式碼包大小的優化:
小程式一開始時程式碼包限制為 1MB,但我們收到了很多反饋說程式碼包大小不夠用,經過評估後我們放開了這個限制,增加到 2MB 。程式碼包上限的增加對於開發者來說,能夠實現更豐富的功能,但對於使用者來說,也增加了下載流量和本地空間的佔用。開發者在實現業務邏輯同時也有必要儘量減少程式碼包的大小,因為程式碼包大小直接影響到下載速度,從而影響使用者的首次開啟體驗。除了程式碼自身的重構優化外,還可以從這兩方面著手優化程式碼大小:

控制程式碼包內圖片資源:
小程式程式碼包經過編譯後,會放在微信的 CDN 上供使用者下載,CDN 開啟了 GZIP 壓縮,所以使用者下載的是壓縮後的 GZIP 包,其大小比程式碼包原體積會更小。 但我們分析資料發現,不同小程式之間的程式碼包壓縮比差異也挺大的,部分可以達到 30%,而部分只有 80%,而造成這部分差異的一個原因,就是圖片資源的使用。GZIP 對基於文字資源的壓縮效果最好,在壓縮較大檔案時往往可高達 70%-80% 的壓縮率,而如果對已經壓縮的資源(例如大多數的圖片格式)則效果甚微。

及時清理沒有使用到的程式碼和資源:
在日常開發的時候,我們可能引入了一些新的庫檔案,而過了一段時間後,由於各種原因又不再使用這個庫了,我們常常會只是去掉了程式碼裡的引用,而忘記刪掉這類庫檔案了。目前小程式打包是會將工程下所有檔案都打入程式碼包內,也就是說,這些沒有被實際使用到的庫檔案和資源也會被打入到程式碼包裡,從而影響到整體程式碼包的大小。

下面將會講解一些開發中遇到的問題:

列表繫結渲染資料、跳轉傳值、小程式的工具除錯使用、小程式授權彈窗、小程式客服反饋、小程式支付、小程式獲取unionId和openId、小程式第三方框架、UI庫等。

持續更新中,敬請關注... ...