小程序開發日記

這裏主要記錄這段時間開發小程序過程當中遇到的坑和要注意的點。主要是但願在之後開發小程序的過程當中能在評審需求的時候就發現哪些能實現,哪些實現起來比較困難。這樣就能在定設計和交互以前儘量的減小後期踩坑的風險。javascript

下拉刷新

自定義的下拉刷新

微信自帶的下拉刷新須要在配置中開啓:html

  1. 配置 app.json 中的 window或者單個頁面的json文件
屬性 類型 默認值 描述
backgroundTextStyle string dark 下拉 loading 的樣式,僅支持 dark / light
enablePullDownRefresh boolean false true 開啓 false關閉
  1. 頁面中經過onPullDownRefresh方法監聽下拉動做
onPullDownRefresh() {
    setTimeout(() => {
      wx.stopPullDownRefresh()
    }, 1000)
  }
複製代碼

這裏有個要注意的問題:
onPullDownRefresh中不能調用wx.startPullDownRefresh(),不然會死循環java

自定義的下拉刷新,目前只支持整個頁面的下拉刷新,對於局部的下拉刷新,就沒有辦法了:android

局部的下拉刷新ios

foo

這種咱們可使用自定義下拉刷新的方式來實現。詳細的能夠看個人另外一篇博客,這裏也就不贅述了。web

關於自定義頂部navigationBar

小程序自帶的navigationBar僅能夠在json文件中配置。提供的可配置項也是少的可憐。主要以下:chrome

屬性 類型 默認值 描述
navigationBarBackgroundColor HexColor #000000 導航欄標題文字內容
navigationBarTextStyle string white 導航欄標題顏色,僅支持 black / white
navigationBarTitleText string 導航欄標題文字內容

從上面的表格能夠看出來,頂部導航欄樣式固定,咱們僅能夠修改文字,字體顏色和背景色。json

不過還好小程序還提供了自定義頂部導航的配置,window.navigationStyle,這個配置項支持兩個值default|custom。默認是default,表示的是用小程序自帶的導航欄,配置爲custom時是自定義導航欄,其實就是小程序隱藏掉導航欄,而後咱們本身實現。canvas

可是自定義導航欄不只帶來了設計上的自由,也帶來了不少坑。小程序

下拉刷新

不一樣於web開發,小程序和app對於下拉刷新的需求很是的多,也算是基本功能之一,小程序自己也自帶下拉刷新。咱們只需將window.enablePullDownRefresh設置爲true,而後在頁面監聽onPullDownRefresh便可。

可是當咱們用到自定義navigationBar的時候,會發現,原本fixed定位在頂端的navigationBar會被一塊兒拉下來。

系統自帶的navigationBar的下拉刷新

foo

自定義navigationBar的下拉刷新

foo

這個時候咱們就必需要使用自定義的下拉刷新。關於自定義的下拉刷新的實現原理這裏就很少說了。可是實現起來在真機中發現,android手機會有明顯的卡頓。

層級問題

按照正常的navigationBar,通常這個組件的層級是最高,僅次於遮罩層和彈窗這些組件。通常的組件可使用z-index屬性來控制層級。

可是小程序中有種概念叫作:原生組件

這些組件包括cameracanvasinput(僅在focus時表現爲原生組件),maptextareavideolive-playerlive-pusher

這種組件脫離於WebView渲染流程以外,層級也是最高的,所以不管z-index設置多大,都沒法覆蓋原生組件。

系統自帶的navigationBar

foo

自定義navigationBar

foo

雖然理論上咱們能夠用cover-viewcover-image來實現自定義的navigationBar,可是我的以爲仍是儘可能避免使用自定義的navigationBar

雖然cover-viewcover-image組件能夠覆蓋在部分原生組件上面。對於原生組件之間,可使用z-index來控制他們的層級。

可是小程序cover-view組件內部只支持嵌套cover-viewcover-image以及button。這在很大程度上不支持咱們做出多麼有個性化的組件。並且實現起來坑也不少。

並且關於用z-index來控制層級這點也存疑,雖然文檔上這樣說明,可是,我在開發中發現,實際上仍是看渲染的順序。後渲染的始終在先渲染的上層。

鍵盤彈起時會將頂部導航欄頂上去

這個是針對textarea組件在頁面底部的時候,準確來講是textarea組件距離底部的距離沒有鍵盤高的時候。在鍵盤彈起時形成了整個頁面上移,從而致使了導航欄會移到頁面外。

當鍵盤未彈起時

foo

當鍵盤彈起時

foo

固然這個不算是硬傷,畢竟出現的條件有限,咱們能夠在設計上儘可能避免將textarea放到底部來避免這個坑。

自定義底部tabbar

自定義的tabbar

在說自定義以前先看看小程序自帶的tabbar能夠作到什麼程度。

自定義的tabbar是在app.json中配置的,在tabBar下:

  • 基本配置
屬性 類型 描述
color HexColor tab 上的文字默認顏色,僅支持十六進制顏色
selectedColor HexColor tab 上的文字選中時的顏色,僅支持十六進制顏色
backgroundColor HexColor tab 的背景色,僅支持十六進制顏色
borderStyle string tabbar上邊框的顏色, 僅支持 black / white
list Array tab 的列表,詳見 list 屬性說明,最少2個、最多5個 tab
position string tabBar的位置,僅支持 bottom / top
custom boolean 自定義 tabBar,見詳情
  • list選項配置
屬性 類型 描述
pagePath string 頁面路徑,必須在 pages 中先定義
text string tab 上按鈕文字
iconPath string 圖片路徑,icon 大小限制爲40kb,建議尺寸爲 81px * 81px,不支持網絡圖片。當 position 爲 top 時,不顯示 icon。
selectedIconPath string 選中時的圖片路徑,icon 大小限制爲40kb,建議尺寸爲 81px * 81px,不支持網絡圖片。當 position 爲 top 時,不顯示 icon。

因此從上面咱們能夠看到,咱們能夠定義tabbar的選中和未選中圖標和字體顏色。沒辦法加入別的樣式和嵌入別的自定義點擊事件。

自定義的幾種實現方式

  1. 組件形式

這是比較老的版本的形式。在須要tabbar的頁面嵌入tabbar組件。這是最簡單的實現方式。可是在首次切換的時候,會有很明顯的閃屏。

  1. 官網提供的customer-tab-bar的形式

這個比第一種要好點,也是我在項目中用到的一種模式,可是切換的時候也有稍微的閃屏

  1. tabbar的形勢

這種實現方式稍微複雜,也就是將首頁的幾個頁面做爲組件傳入,經過路由控制頁面切換。

之因此叫僞tabbar的形勢,是由於這個只是表面上是tabbar

理論上這種方式實現的在切換的時候能夠作到不閃屏。可是會不會帶來別的問題呢?

好比說返回的時候會不會形成頁面錯亂?
本來的頁面生命週期和組件的生命週期略有不一樣,會不會形成一些坑?
還有個幾乎能夠確定的問題,就是若是不使用cover-view的話,咱們就無法蓋住原生組件。

不過好在小程序組件和頁面之間的切換很方便,特別是在用Taro以後,組件和頁面的區分僅僅只是是否在app.tsx中註冊。因此第二和第三種實現方式切換起來並非很麻煩。可是目前看來的話第二種實現方式體驗還算滿意,所以也沒有必要切換到第三種方式。

關於彈窗

額,其實我說的這三個,幾乎能夠總結出一個問題,那就是小程序中讓人吐血的層級問題。

其實不管是彈窗仍是navigation仍是tabbar他們都有一個特色,就是定位在頁面的某一個位置,還有層級要足夠高,要可以覆蓋住底層元素。

官方沒有專門的彈窗容器(我以爲應該有一個彈窗容器)所以只能靠咱們本身寫了。可是由於cover-view使人蛋疼的樣式支持度,我的以爲僅僅用cover-viewcover-image來實現一個定製化的彈窗幾乎不可能。

若是不用cover-view你會發現不少經常使用的組件都是騎在你臉上,而你毫無辦法的。

所以我的建議,在有原生組件的頁面上,儘可能避免彈層的出現。

若是是在沒法妥協,那也建議彈窗組件分兩塊來寫,一種專門用cover-viewcover-image來寫,而且必定要寫z-index來控制層級,理論上是後面的元素會覆蓋在上一個元素上面,可是仍是要防止有些組件在操做的過程當中從新渲染,而改變原有的層級。而對於頁面中沒有原生組件的,能夠用view來寫,這樣樣式上就自由不少。

關於html2wxml

關於富文本的渲染。如今基本的作法都是先把html解析爲節點信息,而後再經過模板渲染爲wxml。可是由於小程序模板不支持遞歸調用。因此在不少第三方組件中都出現如下的代碼:

<!--temp0-->
<template>
...
  <template is="temp1"></template>
</template>
<!--temp1-->
<template>
...
  <template is="temp2"></template>
</template>
<!--temp2-->
<template>
...
  <template is="temp3"></template>
</template>
...
複製代碼

一般這種代碼會出現十幾到二十幾個,也就是說最多支持嵌套二十多層。若是不夠的話就得本身加了。我就遇到過一個富文本,足足嵌套到了兩百多層。我複製到一百的時候實在受不了了,寫了一個模板生成器來完成。

網上有人說這種代碼看起來蠢哭了。的確,可是也很無奈。

時間格式化問題

這個不能說是小程序的坑,應該說是ios和android對new Date()處理上的差別。咱們能夠用safari瀏覽器和chrome來複現這兩種差別

咱們公司先後端交互用的時間格式是YYYY-MM-DDTHH:mm:ss。這種格式的時間字符串用new Date()來處理,在safarichrome的表現以下:

new Date('2019-05-29T14:00:00')
// safari Wed May 29 2019 22:00:00 GMT+0800 (CST) = $2
// chrome Wed May 29 2019 14:00:00 GMT+0800 (中國標準時間)
複製代碼

safari是比chrome要早8小時的,這是由於chrome認爲這個時間是本地時間,而safari認爲是國際標準時間,因此會有這樣的8小時差別(僅限於中國)。

所以在調用new Date()以前咱們須要把YYYY-MM-DDTHH:mm:ss格式的轉換爲YYYY/MM/DD HH:mm:ss這種格式的字符串。

此外,我在處理的過程當中還發現帶毫秒數的事件字符串2019-05-29T14:00:00.000,這種的還須要將毫秒數去掉變成這種格式2019/05/29 14:00:00。而後在iosandroid上表現也就一致了。

function getDate(date: any) {
  if(typeof date === 'string') {
    return new Date(date.replace('T', ' ').replace(/\-/g, '/').split('.')[0])
  }
  return new Date(date)
}
複製代碼

字體

小程序在android下,字體的font-weight必需要設置到700及以上纔會變粗,或者統一使用bold

ios

foo

android

foo

小程序分包

小程序大小是有限制的,目前是主包不超過2M。但是爲了實現一些功能,致使咱們很容易就超過了這個限制。

好在官方提供了分包方式。具體能夠參照官方文檔

就一點:對於副包內引用的,較大的包,應該包含在分包的文件夾內部。否則仍然會打包在主包內部

關於pxrpx

不能無腦的全站用rpx來作適配

最近在作一個需求,以爲有個點仍是須要注意的,特此記錄一下。

這個需求就是一個簡單的消息輪播。以下圖:

foo

就是紅框區域的一個向下無限滾動輪播,時間間隔爲2s。我是使用translateY來實現的。每次translateY的高度和消息塊的高度相同。

可是在滾動的過程當中,發如今某些機型上面每次滾動都會有細微的偏移,而在某些機型上面正常。

消息顯示窗口的高度和每一個消息的高度都是80rpx。代碼以下:

<View className="notice-pannel" style={{transform: `translateY(${curIndex * -80}rpx)`, transition}}>
{
  list.map(item => (
    <View className="notice-item" key={item.id}>
      <Image className="notice-avatar" src={item.actor.avatar_url}></Image>
      <Text className="notice-desc">{`${item.actor.login} ${item.payload.action} ${item.repo.name} at ${new DateX(item.created_at).format()}`}</Text>
    </View>
  ))
}
</View>
複製代碼

最後定位問題的緣由是由於部分屏幕寬度在換算rpx的時候會有偏差,致使每次translateY的時候會有一個小偏差。

rpx根據官方文檔的定義是:rpx(responsive pixel): 能夠根據屏幕寬度進行自適應。規定屏幕寬爲750rpx。

所以,會有些屏幕寬度在rpx轉px的時候會有除不盡的時候,這時候每每會有四捨五入取整的狀況。

在看這行代碼${curIndex * -80}rpx),假設咱們的設備的屏幕寬度爲412這時候80rpx專成px的時候是43.946666666666665px。開發者工具上會發現,其實是換算成了43,也就是每一個消息塊的高度是43px

curIndex2的時候,實際上咱們應該偏移43 * 2也就是86px,但是若是是直接用rpx的話,咱們發現會是87px。這時候就產生了偏移了。

知道緣由的話解決方案也有了,就是用px作單位就能夠了

<View className="notice-pannel" style={{transform: `translateY(${curIndex * rpx2px(-80)}rpx)`, transition}}>
{
  list.map(item => (
    <View className="notice-item" key={item.id}>
      <Image className="notice-avatar" src={item.actor.avatar_url}></Image>
      <Text className="notice-desc">{`${item.actor.login} ${item.payload.action} ${item.repo.name} at ${new DateX(item.created_at).format()}`}</Text>
    </View>
  ))
}
</View>
複製代碼
相關文章
相關標籤/搜索