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