一、背景
在上次和小伙伴分享了快應用(后面簡稱hap)后,有很多待定的思路沒有去嘗試。這周有時間簡單開發了一個熱門微博的應用,主要涉及到的難點:富文本、長列表、畫廊。這里將整個開發過程中遇到的問題以及解決思路和方法分享給大家,希望對想踩坑的各位有所幫助。
代碼:https://github.com/SmileSmith/quickapp-weibo
PS:快應用目前好像還沒有發布正式版,中間會包含一些吐槽(紅字),歡迎指導和拍磚~
二、開發問題和難點記錄
1、前期准備
注意package.json中的toolkit和packager的版本號,表明hap工程toolkit的版本,建議執行 hap update --force更新到最新版本,支持更多特性。
"toolkit": "0.0.30",
"packager": "0.0.5"
例如在【原創】快應用QuickApp--HelloWorld體驗中,這個版本還是0.0.26,babel還不支持stage2。目前0.0.30版本已經默認支持。
執行 hap update --force會導致.babelrc和.eslintrc.json被刷新,請注意。
2、目錄結構
因之前項目的習慣,不喜歡直接將頁面的文件夾放在src下面,改為統一放在src/pages下,在mainfest.json修改如下
"router": { "entry": "pages/Home", "pages": { "pages/Home": { // 加上pages/ "component": "index" }, ... }, "display": { "titleBarBackgroundColor": "#e6162d", "titleBarTextColor": "#eeeeee", "menu": true, "pages": { "pages/Home": { // 加上pages/ "titleBarText": "主頁", "menu": false }, ...
3、內部接口封裝
內部接口中涉及異步操作的,大部分和微信小程序一樣使用 success、fail 的回調實現。為方便后續開發,用Promise簡單封裝了內部接口,並保持接口名稱與微信小程序一致。然后在app.ux中全局導入$app中。
這樣,在各個頁面中就不需要反復寫 import router from '@system.router'; 或 var router = require(''@system.router''),直接使用this.$app.api()即可。
詳情見src/utils/mv.js、src/utils/app.ux
4、長列表使用內部組件List
請先參考官方List教程說明,注意下面的性能優化建議,這里着重說明幾點:
1、List通過對不同結構的列表元素設置不同type,對列表的元素設置唯一的tid,以實現DOM結構復用,提升滑動和渲染的性能表現
2、官方說明中使用對象池概念的memList,在數據量大的情況下會導致渲染對象List丟失,這點和小程序很像。所以本項目沒有使用memList的做法
3、目前遇到兩個問題
(a) List中的子組件使用if和for進行判斷渲染時,會刷新不及時。表現為:修改了if中的條件,但是界面沒有刷新
(b)在List中嵌套for循環,for循環的子組件如果是可復用的DOM標簽,會導致DOM節點被錯誤復用。表現為,下圖中a微博的圖片出現在b微博中。
<block for="(picIndex, pic) in backPics"> // image標簽會因為復用,混亂地出現在不同的子元素中 <image if="{{showIndex === picIndex}}" class="picture {{enterClass}}" src="{{pic}}" @swipe="changePic()"></image> </block>
<text class="gallery"> // text中的span是行元素,不會復用,在List中嵌套這樣的組件可以正確得渲染到各個父組件上 <block for="(picIndex, pic) in backPics"> <span if="{{showIndex === picIndex}}" class="picture {{enterClass}}" src="{{pic}}" @swipe="changePic()"></span> </block> </text>>
4、富文本
官方的rich-text支持快應用格式的html字符串,所以微博接口返回的原生html字符串中含有<icon></icon>等表情,不能使用。
項目參考在小程序中的做法,先用正則過濾,並遍歷形成內容數組,然后在template中for循環出來。詳情見 src/components/richContent.ux
目前有個問題:
用text嵌入span和a,text中不支持image或其它形式的圖片,無法展示表情icon。
如果采用div嵌入text、a和image,又會遇到List中元素錯亂問題。
5、畫廊展示大圖
開始的做法,開發一個gallery組件,放在全局,然后通過消息控制,然而還是遇到List渲染問題。
目前采用頁面的做法,通過路由傳參數。一是可以做到全屏,二是避開List優化的問題。詳情見 src/pages/Gallery/index.ux
利用stack覆蓋的特性,將小圖和加載動畫放在下面,然后等待大圖加載,大圖加載完畢后會覆蓋小圖和加載動畫。
<stack class="gallery"> <block for="(picIndex, pic) in backPics"> // 在列表中已經加載好的小圖,保證用戶能第一時間看到內容,雖然是模糊的 <image if="{{showIndex === picIndex}}" class="picture {{enterClass}}" src="{{pic}}" @swipe="changePic()"></image> </block> <progress class="load-progress" type="circular"></progress> // 加載動畫 <block for="(picIndex, pic) in showPics"> // 大圖,等待加載完畢后覆蓋小圖和動畫 <image if="{{showIndex === picIndex}}" class="picture {{enterClass}}" src="{{pic}}" @longpress="longpress" @swipe="changePic()"></image> </block> <div show="{{showIndex > 0}}" class="button left-button" @click="changePic({direction: 'right'})"><text>«</text></div> <div show="{{showIndex < showPics.length - 1}}" class="button right-button" @click="changePic({direction: 'left'})"><text>»</text></div> <div class="button back-button" @click="closeGallery"><text>︽</text></div> </stack>
目前有個問題:
同一元素不支持同時監聽click和swiper事件,所以無法實現點擊返回列表
大圖渲染問題,實測大圖在高寬比不超過屏幕時,顯示正常;超過時(如長圖片)會導致渲染模糊,越長越模糊:
5、樣式類問題
- 沒有樣式繼承,div中寫的font-size只無效的,必須寫在對應的text或span中
- justify-content 不支持 space-around,可以用容器包裹,容器padding實現。
- position只有fixed,要實現relative用padding調整位置
- border不支持border-left寫法,需要border: 0px solid #eeeeee; border-left: 1px;
5、Debugger
在調試器中點擊開始調試,在代碼中打上debugger,就能調試了。
三、總結
快應用整體還處於beta階段,許多特性還有問題,希望官方盡快解決吧。整體寫法偏向小程序,以后類似mpvue的東西應該也會出現;性能優於小程序,目前生態小,最大的問題還是推廣。。。
1)組件 √
2)路由 √
3)原生接口 √
4)全局狀態管理:考慮繼承mobx或類似的flux組件
5)類型檢測: 考慮用ts