本期想要和大家分享下大眾點評點餐小程序中View視圖層的一些開發經驗。本文部分示例來自于「大眾點評點餐」小程序的菜單頁面。頁 ...
本期想要和大家分享下大眾點評點餐小程序中View視圖層的一些開發經驗。本文部分示例來自于「大眾點評點餐」小程序的菜單頁面。
頁面代碼結構為:
menu
├── menu.html
├── menu.js
├── menu.json
└── menu.less
我們將要說的小程序的View視圖層是由WXML(menu.html) 與 WXSS(menu.less) 兩大部分組成,由視圖最小單元 - 組件來進行展示。視圖層將邏輯層的數據(menu.js+menu.json)反應成視圖,同時將視圖層中定義的事件發送給邏輯層,一圖以蔽之。
WXML(WeiXin Markup Language)與HTML對應,用于描述頁面的結構,可以類比React的JSX。項目中menu.html為WXML語法,一個頁面的頂層是page節點。WXML中獲取邏輯層定義的數據后,通過一系列自己的語法和邏輯展示出這些數據。結構上組件是其最小單元,通過以下方式動態渲染。
數據綁定是最簡單的使用數據方式,語法采用Mustache的變量替換,用雙大括號將變量包起來,如果組件的屬性則需將數據放置于引號之中。
<view class="dish-item" data-id="{{dishId}}"><text class="name">{{dishName}}</text></view>
數據綁定還支持ES6規范的擴展運算符 “...”、解構賦值。
<template is="dishItem" data="{{...item, count, soldout: true }}"></template>
雙大括號中可進行算數運算、三目運算、邏輯判斷、字符串拼接等操作。
<text class="{{orderBanner.type !== 0 ? 'order-banner arrow' : 'order-banner'}}">{{orderBanner.text}}</text>
與常用模板語言將渲染內容寫在 if/else 判斷條件之中不一樣的是,小程序的條件渲染將渲染條件直接寫在渲染內容組件的 wx:if/wx:else 屬性中,如果渲染組件為多個,可將多個組件放在
if/else
<text wx:if="{{item.soldOut}}" class="status-soldout">已售完</text>
<template wx:else is="numberCount" data="{{count: cartSpuCount[item.spuId]}}"></template>
<block>
<block wx:if="{{serverError}}">
<text>點小評去吃滿漢全席啦~</text>
<button class="menu-btn" bindtap="requestMenu">重試</button>
</block>
列表渲染是將遍歷元素作為渲染組件的wx:for屬性值,與此相關的還有以下幾個屬性:
項目中數據較為復雜,使用測試數據舉例:
<block wx:for="{{testData}}"
wx:for-item="mainitem"
wx:key="{{mainindex}}"
wx:for-index="mainindex">
<view wx:for="{{mainitem}}"
wx:for-item="subitem"
wx:key="{{subitem.id}}"
wx:for-index="subindex">
<view class="dom-item">第一層index: {{mainindex}} id: {{subitem.id}} name: {{subitem.name}}</view>
</view>
</block>
以上代碼結構上分為兩層:
1、第一層block循環遍歷testData數組,每個遍歷值變量名為mainitem;
2、第二層view循環遍歷mainitem數組,每個遍歷值變量名為subitem,展示第一層index,第二層id和name屬性;
// 創建頁面實例對象
Page({
/**
* 頁面的初始數據
*/
data: {
"testData": [
[ {
"id": "1-1",
"name": "節點1 - 1"
}, {
"id": "1-2",
"name": "節點1 - 2"
}], [{
"id": "2-1",
"name": "節點2 - 1"
}, {
"id": "2-2",
"name": "節點2 - 2"
}]
]
}
})
展示結果:
開發過程中曾碰到
注意:
如將上面例子中testData換成對象類型:
// 創建頁面實例對象
Page({
/**
* 頁面的初始數據
*/
data: {
"testData": {
"a": [{
"id": "1-1",
"name": "節點1 - 1"
}, {
"id": "1-2",
"name": "節點1 - 2"
}],
"b": [{
"id": "2-1",
"name": "節點2 - 1"
}, {
"id": "2-2",
"name": "節點2 - 2"
}]
}
}
})
結果為:
模板類似于React中的組件component的概念,可以在模板中定義代碼片段,然后在不同的地方調用,減少重復的代碼。
1、定義:使用name屬性,作為模板的名字,然后在<template/>內定義模板代碼片段;
2、使用方式有2種:
注意:
示例(單個菜品組件):
<import src="../../components/common/dish-item.wxml" />
<template is="dishItem" data="{{...item}}"></template>
事件名稱為字符串,會默認傳入event參數,無法定制其他參數,所以一般將所需參數通過data-屬性綁定至組件后通過e.currentTarget.dataset獲取。
<view class="cart-btn" data-type="1" bindtap="redirectCart">選好了</view>
WXSS(WeiXin Style Sheet)與CSS對應,用于描述頁面的樣式。
定義在app.less中的樣式為全局樣式,作用于每一個頁面;在page的wxss文件中定義的樣式為局部樣式,只作用在對應的頁面,并會覆蓋app.less中相同的選擇器,如代碼結構中menu.less作用于menu.html。
注:綠色背景色行表示官方文檔中沒有說明,但經個人親測后確定也支持的選擇器。
目前不支持的選擇器有:
建議:開發微信小程序時設計師可以用 iPhone6 作為視覺稿的標準。
注意: 由于數值較小時渲染時會存在四舍五入的情況,在較小屏幕上差距會很大,所以要求精確而較小的視圖內容需避免使用此單位。
如下圖所示菜品的減號操作圖標,高度iPhone6(750)下是2px,iPhone4s(640)下直接渲染成了1px(實際比例值為1.7px),而加號按鈕圖標高度iPhone6(750)下是11px,iPhone4s(640)下渲染成了9px(實際比例值為9.48px),誤差比例較小沒有出現明顯視覺問題,所以兩者看起來會不協調。
如上WXML中所述,組件是視圖層的基本組成單元,與HMTL中標簽作用類似,基于Web Component標準,屬性和內容的使用方法也和HTML標簽類似,組件和屬性都須小寫。
如上統計,input、textarea、video、map、canvas為系統原生組件。原生組件相對來說性能和用戶交互方面會有所提升。
以部分機型input元素fixed時喚起鍵盤被遮擋的問題舉例,在某魅族機型上H5頁面中父元素fixed的輸入框會被遮擋:
同一機型小程序中,輸入框不會被遮擋:
支持類型
共同屬性
特殊屬性
特殊屬性是各個組件自己定義的屬性,如 <icon> 組件的size屬性,具體各參見官方文檔各組件具體說明。
渲染機制
根據官方文檔的說明:
由于內核渲染表現不一致,H5開發過程中存在X5瀏覽器和各類機型或系統的兼容性的部分問題小程序中依舊存在。
常見問題分類
前端常用的模板方案一般有2種:
當數據改變觸發渲染層重新渲染的時候,會校正帶有key的組件,框架會確保他們被重新排序,而不是重新創建,以確保使組件保持自身的狀態,并且提高列表渲染時的效率。
小程序對組件的渲染方式我們不得而知,只能對開發中碰到的一些問題來推測。結合小程序對列表渲染wx:key的解釋可知其模板渲染屬于第二種,數據更新時會根據key進行渲染優化。但小程序官方未提供相關接口或性能調試工具,所以項目中我們只能自己嘗試不同方案然后對比渲染速度。以菜單頁面為例,商戶菜品數量多者成百上千,優化后的效果對比還是比較明顯。
采取方案
本文時間為2017-02-24,所提小程序暫不支持屬性或碰到的bug以此時間為準,后續更新或修復請查看官方文檔。