微信小程序從發布開始,可謂賺足了眼球,一度引發了開發界“全民學JavaScript”的梗。
為了跟上時代步伐,我們NOW直播團隊也在發布后第一時間嘗鮮,本文就來扒一扒這幾天試水小程序開發的那些事。
想要開發微信小程序,首先必須要有一個微信公眾平臺小程序的帳號(目前帳號只有內測邀請唯一途徑),此帳號用于獲取app id、secret id、添加開發者等管理后臺操作。
然后你需要下載官方提供的微信web開發者工具,這是一個集成了編碼、調試、預覽、發布功能的一個IDE。
編碼功能:
調試功能,集成了chrome開發者工具,可以實現樣式預覽、JS斷點調試等:
發布、預覽功能,可以在此上傳你的程序,預覽生成二維碼,提供在手機微信上預覽小程序的功能;另外,開發者工具還集成了ES6編譯、代碼壓縮等基礎代碼構建功能:
對于哪怕是只有一點點web前端經驗的開發者來說,微信小程序的入門門檻簡直是低到不能再低了。
一個小程序的主要文件目錄簡潔到如下:
├─ app.json
├─ app.wxss
├─ app.js
└── pages
├─ index
│ ├─ index.wxml
│ ├─ index.wxss
│ └─ index.js
└─ my-page
├─ my-page.json
├─ my-page.wxml
├─ my-page.wxss
└─ my-page.js
一個小程序大體上分為兩大塊:
應用實例app
頁面pages
小程序會讀取根目錄的app.json
,app.js
,app.wxss
生成程序實例,當然樣式文件不是必需的。
app.json
// app.json
{
"pages":[
"pages/index/index"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
在這個文件里可以針對以下內容作小程序的全局配置:
頁面文件的路徑
網絡超時時間
程序級tab配置
窗口顏色
手機導航欄、小程序標題欄的背景色、字體色,下圖是設置了導航欄顏色為綠色的效果:
app.js
每一個小程序都是通過App({/*configs*/})
這樣一個App方法來注冊的,在其具體的配置中,我們可以監聽并處理程序級的生命周期函數、聲明全局變量。比如,需要設置程序啟動、顯示時的一些操作,設置一些程序全局的數據、變量、方法,都可以在這里完成。
//app.js
App({
onLaunch: function () {
// do something
},
global: {
data: null
}
})
在app.js
里聲明的屬性及方法,都可以在小程序的任意頁面里訪問到:
// page.js
//獲取應用實例
var app = getApp()
Page({
doSth: function() {
console.log(app.globalData);
}
})
app.js里支持的的程序級的生命周期回調包括:
onLaunch 小程序初始化完成時觸發
onShow 啟動,從后臺進入前臺顯示時觸發
onHide 從前臺進入后臺時觸發
一個頁面簡單講可以理解成小程序的一個完整界面單元,每一次完整的界面切換就是page
之間的跳轉,下圖演示一個典型的頁面切換、回退過程:
一個頁面的組成部分包括:
視圖層
WXML(WeiXin Markup language)
用于描述頁面的結構
WXSS(WeiXin Style Sheet)
用于描述頁面的樣式,非必需
邏輯層
JS
控制頁面行為及數據變化
JSON
頁面級配置,非必需
視圖層與邏輯層統一通過數據
和事件
相互聯系起來,用一句話描述就是:數據驅動。
如果你有使用過React、Vue(或其他MVVM框架)等,對于“數據驅動”肯定一點都不陌生了,沒錯,小程序毫無疑問吸收了這一開發理念。
來看看一個簡單頁面的代碼:
<!--index.wxml-->
<view bindtap="bindViewTap" class="userinfo">
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}"></image>
<text class="userinfo-nickname">
{{userInfo.nickName}}
</text>
</view>
//index.js
Page({
data: {
userInfo: {
nickName: 'test',
avatarUrl: 'https://a.com/test.png'
}
},
//事件處理函數
bindViewTap: function() {
console.log('觸發了tap');
}
})
這段代碼實現的是一個簡單的頁面效果:
可以看到出:
每一個“頁面”,都是通過JS邏輯層的Page({/*configs*/})
方法來注冊的;
WXML統一通過{{data}}
花括號的方式來引用邏輯層的數據;
視圖層通過bind
+event key
來和邏輯層的事件回調實現綁定;
當邏輯層需要控制視圖層變化時,統一通過關鍵函數setData
來驅動數據變化,間接改變視圖,如:
//index.js
Page({
data: {
userInfo: {
nickName: 'test',
avatarUrl: 'https://a.com/test.png'
}
},
//事件處理函數
bindViewTap: function() {
console.log('觸發了tap');
this.setData({
userInfo: {
nickName: 'test',
avatarUrl: 'https://a.com/change.png'
}
});
}
})
上述代碼中,setData
調用后,頁面圖片就變化了。setData
與React中的setState
真的是有相當的相似之處。
其實,微信小程序是完全不支持DOM操作的,千萬不要想著手動去控制DOM結構。簡單的說,HTML5開發中BOM的那一整套API都沒法使用,包括window、document ......
WXML在近似于HTML外,吸收了很多其他模板標記語言的優點,例如支持:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<view wx:for="{{items}}">
{{index}}: {{item.message}}
</view>
前面已經提到過事件綁定,前端人對于事件還是非常熟悉的,事件是視圖層到邏輯層的通訊方式。
小程序支持的事件類型包括有:
和web事件類似,小程序也支持冒泡事件和非冒泡事件,在綁定過程中通過bind
(冒泡)和catch
(非冒泡)區分:
<!--page.wxml-->
<view id="outter" bindtap="handleTap1">
outer view
<view id="middle" catchtap="handleTap2">
middle view
<view id="inner" bindtap="handleTap3">
inner view
<view id="inner-inner" bindtap="handleTap4">
inner-inner view
</view>
</view>
</view>
</view>
//page.js
Page({
data: {
},
handleTap1: function () {
console.log(1);
},
handleTap2: function () {
console.log(2);
},
handleTap3: function () {
console.log(3);
},
handleTap4: function () {
console.log(4);
}
})
上述程序中,middle view
是關鍵分割點,點擊inner-inner view
,將會依次顯示4,3,2
,因為middle view
中使用了catch
來綁定事件并阻止事件往上層冒泡,middle view
及其子組件的tap冒泡事件都會在它這一層被截斷。
WXML文件中,組件是視圖的基本組成單元,類似HTML的提供的各種標簽,小程序提供了非常全面的組件:
UI容器
滾動UI容器
輪播組件
文本容器
視屏、音頻
表單組件 (輸入框、單/復選、滑動選擇等等navtive表單組件),下圖示例是一個在HTML環境中不好實現的picker組件,通過調用native,來實現絲般順滑的體驗:
彈窗
loading
地圖展示
畫布(canvas)
......
關于樣式,其實沒有什么好說的,作為小程序的UI描述語言,幾乎與CSS無異,寫法、支持的屬性也一樣。不過,樣式文件不是必需的,并且,頁面級的樣式會優先于全局樣式,即index.wxss
的樣式聲明優先級會高于app.wxss
。
前面有說到,頁面作為小程序的界面單元,那么肯定就有頁面間的切換、跳轉、后退等。
以下程序是一個簡單的通過tap動作觸發頁面切換程序:
<!--index.wxml-->
<view class="container">
<text class="a">index</text>
<text>go to </text>
<text class="link" bindtap="bindViewTap">my-page</text>
</view>
// index.js
Page({
data: {
},
//事件處理函數
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
}
})
除了使用wx.navigateTo
方法外,還可以使用wx. redirectTo
,這兩者的區別是,前者打開的頁面中,可以直接返回原來頁面切換前的狀態;而后者則是完全關閉當前頁面打開新頁面,返回時,原來的頁面只能“重新渲染”。
區別于HTML5應用,小程序為每個頁面提供了一些更強大的生命周期和用戶操作回調函數:
以往的產品開發中,如果選用HTML5來開發,性能上一般會比native要差一些,而選用native開發,則一般有比較長的版本發布周期。
微信小程序的出現,使得我們在開發native應用的同時,再也不用忍受漫長的版本發布,只要我們編寫好了小程序上傳,微信就可以通過后臺實現客戶端的熱更新,在產品性能、發布體驗上,都達到了質的提升。
雖然開發小程序非常接近于HTML5開發,但是本質上,它已經不再是web,它更像是React Native這樣的native開發框架,通過JSBridge
,串聯起native底層和上層的JS、WXML邏輯。
它通過封裝微信客戶端提供的文件系統、網絡通信、任務管理、數據安全等基礎功能,對上層提供了一套完整的API,使得開發者能夠非常方便的使用到微信客戶端提供的各種基礎功能,快速構建一個應用。
所以,在以前HTML5階段無法實現或實現起來相當困難的一些功能,在小程序時代將會變得非常簡單。
小程序為我們提供了豐富、簡單的微信原生API,可以方便的調起微信提供的能力或一些系統原生能力:
http請求(ajax)
文件上傳、下載
websocket
本地圖片、音頻、視頻的預覽、播放
本地音頻的暫停、進度等控制
視頻、音頻錄制、預覽、上傳
設備網絡狀態
系統信息(手機型號、設備像素比等)
設備重力感應
羅盤
地理位置信息
動畫、繪圖
數據緩存,類似HTML5的localstorage,同樣有5M的數據存儲限制
微信支付
模板消息(服務通知)
......
小程序嚴格限定了代碼的文件、目錄結構,即同名依賴識別:
├ pages
├─ index
│ ├─ index.wxml
│ ├─ index.wxss
│ └─ index.js
└─ my-page
├─ my-page.json
├─ my-page.wxml
├─ my-page.wxss
└─ my-page.js
至少在應用、頁面的核心代碼這一塊,開發者沒有必要也不允許自定義自己的目錄結構;
另外,結合官方提供的開發者工具,無需操心ES6的編譯、代碼壓縮等構建問題。
微信小程序的出現,給我們帶來了接近HTML5、跨平臺的開發體驗,帶來了接近原生應用的產品體驗,然而在我們的實踐中,還是品嘗到了一些不是那么完美的體驗。
小程序確實提供了類似HTML5的video
組件,用于視頻播放,然而把它遠遠還沒達到HTML5的video
那么強大:
個人直播業務,基本所有的主播信息、點贊、評論、禮物等等展示都是覆蓋于視頻之上,如下圖:
可是目前的小程序里提供的video組件,會強制所有其他元素必須在其之下,類似CSS中的z-index值,它永遠是最高的,這樣想通過absolute定位等方式實現漂浮禮物動效等業務需求,變得不可行。
小程序提供了一個HTTP請求接口wx.request({/*configs*/})
,可以實現類似Ajax的功能,然而當我們使用現有的業務接口時,卻遇到了困難。
在瀏覽器環境下,我們的后臺接口作了很多安全限制,最基本的一項就是請求的referer限制,必須是本域請求才能通過。然而,微信小程序明確規定,wx.request
這個方法中不允許設置Referer。所以,如果你們的業務有類似我們的這樣的后臺接口時,會面臨一些接口改造。
我們正常的web業務,前后端通信中,對cookie的依賴是無處不在的,但是,小程序作為本質上的native應用,請求是沒有cookie的,我們的程序中,也沒有辦法拿到cookie,所以,對于很多現有的業務接口,直接兼容微信小程序,恐怕沒那么簡單。
小程序提供的唯一鑒權方案需要通過小程序客戶端、業務服務端、微信平臺服務器三方溝通來實現,具體可以看微信官方文檔架構圖:
其實,以上就是目前大部分開發平臺使用的OAuth 2.0標準鑒權方案。
可能是小程序出于戰略考慮,設計上還是相對封閉的,想通過小程序打通現有的業務,包括APP、HTML5網站等等,甚至微信公眾號,都會受到一些限制。
我們曾想過在小程序里提供常見的長按公眾號二維碼識別進入關注界面的功能,目前是無法實現的;另外,想通過小程序打開現有的web頁面、調起系統現有的APP等,目前也是不支持的。