本文的目的不是討論小程序的是或非,只是記錄一下筆者在開發(fā)小程序過程中一些收獲和感想。
有消息稱第一批微信小程序在12月中下旬發(fā)布,在那之前,需要將已完成的小程序向騰訊提交審核。58到家看準(zhǔn)了這次推廣的機(jī)會(huì),制定了小程序開發(fā)計(jì)劃。筆者是主要開發(fā)者之一。
閑話少說,進(jìn)入正題。
小程序號稱使用前端技術(shù)開發(fā)接近native體驗(yàn)的webapp,微信提供了許多js和native交互的bridge API,同時(shí)將html/css進(jìn)行改造,分別對應(yīng)wxml和wxss。初見之時(shí),看上去就是換個(gè)名字而已嘛,都是熟悉的技術(shù),項(xiàng)目分分鐘開發(fā)完成哈哈。然后就興致勃勃的開始折騰,然后就...
小程序官方文檔相當(dāng)“簡潔”,以示例代碼的形式很形象地說明了各模塊的開發(fā)模式。但是示例代碼以及文字描述并未將其中的細(xì)節(jié)完全暴露出來,上手開發(fā)后才發(fā)現(xiàn)很多坑。
wxss乍看上去就是css,名字相似,語法相似。但寫起代碼來真是痛苦的很,下面一一列出目前筆者遇到的問題。
1> 不支持級聯(lián)選擇器
css選擇器可以支持自上而下一層層的級聯(lián)選擇,比如:
.parent .child{ color: #000; }
前端開發(fā)者對此非常熟悉。但是wxss并不支持上述語法,如果使用class作為匹配選擇器,只能寫一層,如下:
.parent{} .child{ color: #000; }
這種模式令開發(fā)者在為class命名上必須不能重復(fù),限制了自由度。
2> 選擇器支持非常有限
目前官方給出的wxss支持選擇器只有以下幾種:
其中的element是wxml支持的標(biāo)簽元素,并非所有html標(biāo)簽。
3> 不支持引用本地圖片資源
比如我們需要使用本地的sprites圖片:
.dj__icon { background-image; url("./assets/icons.sprites.png"); }
如果在wxss中編寫以上代碼并不會(huì)報(bào)錯(cuò),但是也不會(huì)有任何理想的效果。官方給出的答復(fù)是:
所以如果我們需要使用自定義的圖標(biāo)UI的話,目前只能先將sprites圖片上傳到自己的服務(wù)器或者base64編譯后再寫入wxss中。
wxml的語法與vue.js有點(diǎn)相似,支持?jǐn)?shù)據(jù)綁定以及部分模板邏輯。筆者目前在wxml開發(fā)中總結(jié)以下幾點(diǎn)注意事項(xiàng):
1> 使用wxml模板語法時(shí)只能使用部分js邏輯判斷
或者也可以理解為只能使用以下幾種邏輯:
由于wxml使用雙花括號{{}}作為數(shù)據(jù)綁定標(biāo)識,所以被{{}}包裹的邏輯語句不能出現(xiàn)花括號{},否則會(huì)報(bào)語法錯(cuò)誤。比如:
<view>{{ Object.assign({},data,{isTrue: false})}}</view>
2> event handler的參數(shù)event不支持訪問DOM
小程序中不支持任何訪問DOM的語法,因?yàn)樗⒉皇窃跒g覽器環(huán)境下運(yùn)行,所以document、window等瀏覽器暴露的API均不能訪問。事件響應(yīng)函數(shù)接受的event參數(shù)的完整結(jié)構(gòu)如下:
{ "type":"tap", "timeStamp":895, "target": { "id": "tapTest", "dataset": { "hi":"WeChat" } }, "currentTarget": { "id": "tapTest", "dataset": { "hi":"WeChat" } }, "detail": { "x":53, "y":14 }, "touches":[{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14 }], "changedTouches":[{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14 }] }
所以如果想使用常規(guī)瀏覽器環(huán)境下,通過event.target獲取DOM是不可行的。只能通過操作數(shù)據(jù)來修改UI。
3> 使用剩余參數(shù)語法向模板傳遞對象格式的data
wxml支持模板引用以便開發(fā)通用組件,比如項(xiàng)目中存在item.wxml:
<!-- item.wxml --> <template name="item"> <text>{{text}}</text> </template>
在 index.wxml 中引用了 item.wxml,就可以使用item模板:
<import src="item.wxml"/> <template is="item" data="{{text: 'forbar'}}"/>
其中的data是向item.wxml傳遞的參數(shù)。如果要循環(huán)一個(gè)列表數(shù)據(jù),列表中每個(gè)元素都是key-value格式且對應(yīng)一個(gè)item的話,需要使用以下格式:
<import src="item.wxml"/> <template is="item" wx:for="{{list}}" wx:for-item="item" data="{{..item}}"/>
上述代碼將列表的每個(gè)元素整體傳遞給item.wxml,使用data="{{..item}}"語法。當(dāng)然,你也可以在data中添加其他數(shù)據(jù),比如data="{{..item, text:'forbar'}}"。
3> 可將事件響應(yīng)函數(shù)名稱通過data傳遞給組件模板
組件對引用它的模板來說就是一個(gè)黑盒,外部不應(yīng)該干涉組件的內(nèi)部邏輯。如果想要組件響應(yīng)某些操作并反饋外部定義的響應(yīng)函數(shù),可以將外部已定義的響應(yīng)函數(shù)名稱傳給組件。
我們將上文的代碼改造一下演示這個(gè)問題。比如item.wxml暴露了tap響應(yīng)API:
<!-- item.wxml --> <template name="item"> <text bindtap="{{tapHandler}}">{{text}}</text> </template>
index.wxml中引入item組件并傳遞了tapHandler:
<import src="item.wxml"/> <template is="item" data="{{text: 'forbar', tapHandler: 'indexTapHandler'}}"/>
其中indexTapHandler是index.wxml對應(yīng)的js中聲明的響應(yīng)函數(shù):
Page({ indexTapHandler(e){ alert('trigger index tap event'); } });
這樣就完成了組件事件響應(yīng)的定制。
3> 可變數(shù)組數(shù)據(jù)渲染務(wù)必使用wx:key
渲染列表數(shù)據(jù)時(shí),如果列表中的數(shù)據(jù)是動(dòng)態(tài)的(比如點(diǎn)擊之后修改列表中某個(gè)元素的值),那么在渲染UI時(shí)務(wù)必將渲染的模板加上wx:key。請看以下代碼:
<import src="item.wxml"/> <template is="item" wx:for="{{list}}" wx:for-item="item" wx:for-index="idx" wx:key="item-{{idx}}" data="{{..item}}"/>
上述代碼使用列表的index作為wx:key的值,保證每個(gè)元素對應(yīng)template的唯一性。
wx:key的取值還可以是保留字*this,官方給出的定義如下:
保留關(guān)鍵字 *this 代表在 for 循環(huán)中的 item 本身,這種表示需要 item 本身是一個(gè)唯一的字符串或者數(shù)字。
根據(jù)以上的解釋,如果item本身是動(dòng)態(tài)不唯一的,是不能使用*this作為wx:key取值的,否則會(huì)出現(xiàn)非常詭異的情況。
第一天的開發(fā)感想就是:小程序并不像第一眼看上去那么美好,不能把小程序簡單地理解為html+css+js。本文暫時(shí)不討論小程序背后的運(yùn)行原理,單純出開發(fā)層面看,wxss相當(dāng)于極度縮減版的css;wxml是mustache的簡化版。至于js,后續(xù)筆者會(huì)將遇到的問題和經(jīng)驗(yàn)寫出來,以供參考。