- 快應用介紹
- 遇到的問題和解決辦法
- 幾點開發實踐
- 一點感悟
快應用介紹
介紹
網頁:網頁無需安裝,體驗不夠很好;
原生應用:原生應用體驗流暢,但需要從應用商店下載安裝,難以一步直達使用者,而且安裝包比較大耗流量;
快應用:深度整合在手機作業系統中,使用者無需下載安裝直接在手機上執行,可流暢的體驗應用內容。
類似微信小程式,微信小程式巢狀在微信 app 裡面,快應用巢狀在手機系統裡面。
入口比較全,包括:URL 連結、全域性搜尋、應用商店、瀏覽器、負一屏、系統桌面、PUSH、語音助手、安全中心、垃圾清理、資訊助手、天氣、簡訊模板、日曆、個性主題、檔案管理...
開發技術
快應用採用前端技術棧,由基本的標籤、樣式、js指令碼等組成,與 Vue 的開發方式相近。
快應用使用 MVVM 的設計模式進行開發,開發者無需直接操作 DOM 節點的增刪,利用資料驅動的方式完成節點更新。
開發實時編譯渲染,完成後打包生成 rpk 包上傳平臺。
快速開始
- 安裝快應用開發工具:https://www.quickapp.cn/docCe...
- 新建快應用工程
- 程式碼結構
- 開發除錯
- 編譯打包提交測試
- 上傳至官網的開發者中心,提交稽核釋出
遇到的問題和解決辦法
缺點
真實開發體驗感受到的問題:
- 開發工具屬於簡易版的 VS Code,容易卡頓,偶爾會出現詭異的問題
- api 未全部統一,各家廠商都有部分私有的api和功能
- 官方文件不全,不夠詳細
- 更新迭代慢,基礎功能夠用,更細節的功能不夠全
- 社群不繁榮,較少更新維護
- 應用量和開發者較少導致文件和相關資料少,遇到問題很難找到可借鑑的解決方案
遇到的問題和解決辦法
1. 開發工具執行卡頓
現象:長時間執行快應用開發工具會變卡頓。
解決:可以退出殺死快應用開發工具,然後重新開啟。
2. 開發工具執行報錯
現象:初次安裝報錯,開發過程報錯,偶發編譯報錯。
解決:檢視右側預覽報錯資訊 => 檢視底部輸出的報錯資訊 => onError 監聽 => 程式碼二分法排查 => 重啟開發工具 => 重啟電腦
說明:
- 常規明顯的錯誤右側預覽會提示
- 元件內部報錯整個元件會渲染失敗,可檢視偵錯程式輸出查問題
onError
全域性監聽,用prompt.showDialog
彈出全域性報錯- 異常頁面通過二分法依次對半隱藏程式碼找到錯誤
- 未發現異常或者
$app
、$def
、自定義的$config
不存在報錯,清除快取重新編譯,不行再重啟開發工具,再不行重啟電腦
3. 生命週期函式執行問題
頁面執行順序 onInit => onReady => onShow
自定義元件只有 onInit => onReady
現象:載入過一次的頁面返回再進入只會執行 onShow
,此時頁面中自定義元件生命週期函式不會執行。
解決:加上 if
並在頁面 onShow
中修改為 false,100ms 後為改為 true,強制子元件重新整理。
4. 定位不支援 z-index
控制層級
現象:z-index
無效,多個 position
定位元素互相覆蓋時,誰後面渲染誰就在上層。
解決:用 stack
元件替代,stack
容器子元件排列方式為層疊排列,每個直接子元件按照先後順序依次堆疊,覆蓋前一個子元件;用程式碼邏輯控制要顯示在最上層的最後去渲染。
5. 私有自動登入 api 導致預覽無法使用
現象:使用了 oppo 私有的自動登入 api,模組不存在報錯導致開發者工具右側預覽失敗,無法實時開發除錯。
解決:封裝登入方法,引入引數控制除錯階段用寫死的登入 token,不走私有登入 api。
6. 頁面棧過多資料被銷燬
現象:閱讀頁和詳情頁因為 id 不一樣每次都會產生新的頁面棧,頁面棧的數量超過 5個,快取在記憶體裡的最早頁面資料會被銷燬,一般表現就是首頁會變空白,因為最先進的是首頁。
解決:閱讀頁和詳情頁這種帶 id 的頁面用 router.replace
替換 router.push
;監聽頁面棧數量超過 5個記錄一下,在回到首頁的時候重新載入資料。
7. 計時器問題
現象:計時器內函式執行報錯 this
找不到,A頁面跳轉到B,後臺繼續監聽A頁面計時器,到點執行計時器,此時A頁面已被銷燬,報錯。
解決:給 Function
增加 bindPage
方法,在 bindPage
裡面判斷頁面存在才執行函式,所有計時器都用以下方法:
const bindPageLC = () => {
Function.prototype.bindPage = function (vmInst) {
const fn = this
return function () {
if (!vmInst) {
throw new Error('使用錯誤:請傳遞VM物件')
}
if (vmInst.$valid) {
return fn.apply(vmInst, arguments)
} else {
console.error('頁面銷燬時,不執行回撥函式')
}
}
}
}
bindPageLC()
setTimeout(function() {
}.bindPage(this), 500)
8. 系統字型設定變化導致內容錯位
現象:手動修改系統字型大小,未做適配導致頁面錯位,目前未提供相關 api 能監聽到系統字型大小變化導致。
解決:manifest.json
關閉字型大小響應 "textSizeAdjust": "none"
。
9. 系統顯示設定變化導致內容錯位
現象:手動修改系統顯示大小,使用富文字容器內嵌html元素的會變大錯位。"textSizeAdjust": "none"
只能關閉不響應系統字型變化。
解決:不使用富文字容器內嵌 html,改用 div
、text
等元件。
10. 螢幕適配
快應用和負一屏卡片預設尺寸都是 "designWidth": 750
,使用 750 的設計圖可 1:1 寫樣式;
如果 "designWidth": 1080
,375 的圖需要乘以 3,可以在公共樣式裡定義變數,@3:3px;
;
具體使用則:height: 156*@3;padding: 16*@3 16*@3 0;
。
11. 夜間適配
現象:監聽夜間模式然後變換最外層樣式去更換顏色,發現不起作用,需要每個元素都單獨換樣式才有效。
解決:快應用可以夜間媒體查詢適配 @media (prefers-color-scheme: dark) {}
。
manifest.json
中 "themeMode": -1,
跟隨主題色,"forceDark": true,
開啟反色
圖片暗夜 src 替換:監聽主題模式切換 onConfigurationChanged
,獲取當前的主題模式 configuration.getThemeMode()
元件單獨關閉反色:forcedark="false"
自定義樣式:用媒體查詢適配 @media (prefers-color-scheme: dark) {}
12. 閱讀頁豎翻模式 1.0 廣告問題
現象:多個廣告元件 for
迴圈,繫結 appear
觸發載入,每個元件會多次觸發 appear
事件;廣告元件onLoad
回撥會觸發多次。
解決:加索引快取過濾掉已載入過的元件;廣告物件抽離到外部共同引用,傳資料到廣告元件裡面去渲染資料,做資料快取過濾。
13. 2.0 原生廣告注意點
載入:最外層通過 if
重新渲染載入新廣告
成功:返回的資料不再有廣告 id
點選:廣告曝光和點選只會觸發1次,再次點選不會觸發廣告點選上報,無收益;觸發廣告跳轉區域不能用 if
控制,否則點選無任何反應,用 show
控制
關閉:自定義關閉廣告元素用 show
,不用 if
,這樣就不會跳轉到廣告連結
14. 安全稽核問題
loglevel
需設定為 off
;
未同意隱私協議前存在聯網行為:所有請求在同意協議後再發;
不允許存在 http
連結:對介面下發的連結全部轉換成 https
,介面連結支援 http
和 https
,部分下發的還是 http
;
程式碼中不允許存在硬編碼 IP
:可拼接使用;
storage
不允許明文儲存敏感資訊,比如暱稱、手機號等:可用 cipher.aes()
加密儲存。
幾點開發實踐
平臺版本
快應用覆蓋式更新,平臺版本可升級到 1100 最新版
錯誤處理
- JSON.parse 解析報錯處理
const parseJSON = () => {
const rawParse = JSON.parse
JSON.parse = (str, defaults) => {
try {
return rawParse(str)
} catch (err) {
console.error(`JSON 解析失敗:${str}, ${err.stack}`)
return defaults
}
}
}
- 通過 $valid 判斷頁面狀態,解決回撥函式中引用 this 資料包錯
const bindPageLC = () => {
Function.prototype.bindPage = function (vmInst) {
const fn = this
return function () {
if (!vmInst) {
throw new Error('使用錯誤:請傳遞VM物件')
}
if (vmInst.$valid) {
return fn.apply(vmInst, arguments)
} else {
console.error('頁面銷燬時,不執行回撥函式')
}
}
}
}
- 錯誤頁面
監聽 onPageNotFound
,當頁面跳轉異常時跳轉到自定義錯誤頁面,加埋點上報
- 全域性報錯監聽
監聽onError
應用報錯,應用捕獲異常時呼叫,加埋點上報
- 後端伺服器介面請求失敗上報
效能優化
1. 全域性掛載公共函式
global.$config
掛載公共靜態配置資料:$config.bpImg
global.$utils
掛載純函式以及部分系統api的封裝:$utils.formatDate()
app.ux
掛載封裝的快應用方法函式:this.$app.$def.login
2. 合理巢狀 html
html 層級不要超過 28 層,否則會警告;標籤要閉合,否則不會報錯但是渲染的判斷邏輯會不起作用,出現詭異 bug
3. 合理使用 css 選擇器
css 樣式巢狀層級越深,單次匹配耗時越長
避免使用元件(比如 text)名稱作為最後一項匹配規則,否則每個 text 元件渲染時都會遍歷匹配一次
從右到左匹配,最後一位樣式名儘量唯一,較少匹配次數
4. 簡化 ViewModel 資料
快應用會對賦值的響應式資料中每個屬性進行遞迴式的定義,屬性個數的定義越少越好
所以針對陣列型別資料,賦值時可過濾掉不需要用到的物件屬性
5. 使用懶載入
list
元件中,不在螢幕之內的 list-item
可以在滑動時載入更多,完成渲染
tabs
元件中,非當前顯示的頁籤內容,可以在使用者點選頁籤時完成渲染(藉助if指令控制tab-content元件的子節點)
資料傳遞
1. 父子元件傳資料
父元件:props
<==> 子元件:$emit()
觸發繫結的自定義事件
子元件:$dispatch()
觸發自定義事件 <==> 父元件:$on()
監控自定義事件,向外傳遞
父元件:$broadcast()
觸發自定義事件 <==> 子元件:$on()
監控自定義事件,向內傳遞
2. 兄弟元件傳資料
自己寫一個提供釋出訂閱能力的 JS,然後各個 ViewModel
引入這個JS檔案
或者將其掛載在頁面級別的 ViewModel
,子元件通過 $root
引用到頁面級別的 ViewModel
父元件
<script>
import {
createOrRetrieveInst
} from './pubsub.js'
export default {
onReady () {
// 1. 例項化:並繫結在VM上
this.pubsubModel = createOrRetrieveInst()
// 2. 訂閱:其它VM也可以呼叫
this.pubsubModel.subscribe('count-add', function (vArg0, vArg1){ ... })
// 3. 釋出:其它VM也可以呼叫
this.pubsubModel.publish('count-add', ['arg0', 'arg1'])
}
}
</script>
子元件
<script>
export default {
onReady () {
// 1. 訂閱
this.$root.pubsubModel.subscribe('count-add', function (vArg0, vArg1){ ... })
// 2. 釋出
this.$root.pubsubModel.publish('count-add', ['arg0', 'arg1'])
}
}
</script>
3. 跨層級傳資料
app.ux
中:
onCreate() {
this.dataCache = {} // 初始化 app 快取的資料
},
getAppData(key) { // 獲取 app 快取的資料
return this.dataCache[key]
},
setAppData(key, val) { // 設定 app 快取的資料
this.dataCache[key] = val
},
使用:
// 任意頁面設定
this.$app.setAppData('adbooks', JSON.parse(JSON.stringify(adBook)))
// 任意頁面獲取
this.$app.getAppData('adbooks')
快速生成多個快應用
需求:一個快應用為主,衍生出多個換膚、換圖、換問題的快應用
解決:用命令列復制新的配置去覆蓋現有配置再打包,配置項檔案 manifest.json
、variables.less
、公共 config.js
負一屏卡片開發
- 新版負一屏卡片整體空間完全自定義,包括 logo、標題、重新整理頻率,每次滑到負一屏就會觸發1次
onShow
- 卡片載入有系統 loading,自己不需要再加 loading,否則2個 loading 會衝突,載入中間態要用骨架屏
- 快取讀取問題
負一屏卡片要讀取快應用 storage
快取,包名必須一致,不能獨立建包,要把卡片嵌在快應用中,然後在管理平臺建立智慧服務即可
console
檢視
- 電腦安裝
adb
brew cask install android-platform-tools
adb logcat -c
清除log快取資訊adb logcat -v time >./log.log
寫入日誌,然後在日誌檔案中找資訊
- 夜間適配
- 必須適配夜間模式
- 不支援媒體查詢
@media (prefers-color-scheme: dark) {}
- 根據獲取的當前題模式值去動態修改每個元件樣式
一點感悟
做完一個週期的快應用專案,對比靜態頁面、jq、vue、react、小程式、uni-app、electron以及各種衍生的元件庫
核心還是三個東西,html 頁面結構、css 樣式、js 邏輯:
- html 頁面結構這塊寫法、優化、注意項都差不多
- css 寫法也一樣(除了 react 的 css in js 寫法),掌握一套完整的樣式寫法基本能搞定常規業務
- js 核心邏輯寫法也是一樣的
然後會發現各種專案的腳手架、專案結構、使用方法也都差不多,到最後寫的最多的始終是業務邏輯。
這裡就可以整理出一整套自己的專案開發方法然後持續複用:包括專案結構、檔案命名、html 結構、css 命名和寫法、js 常規方法、api 呼叫方法、說明文件、eslint 規則等配置項等等。
舉其中一個點:
經常會用到的訊息提示彈窗
element:
this.$message({
message: '這是一條訊息提示',
type: 'info',
duration: 3000,
...
})
vant:
this.$notify({
message: '這是一條訊息提示',
type: 'danger',
duration: 3000
...
})
antd:
message.success({
content: '這是一條訊息提示',
duration: 3,
...
})
message.loading({
content: '這是一條訊息提示',
duration: 3,
...
})
微信小程式:
wx.showToast({
title: '成功',
icon: 'success',
duration: 1500
})
uni-app:
uni.showToast({
title: '這是一條訊息提示',
icon: 'success',
duration: 1500
})
快應用:
prompt.showToast({
message: 'message',
duration: 0
})
這些框架、元件庫基本用法和原理是類似的,最大的區別在於 api 的命名以及引數的差異,每個都去記住費勁又費記憶。
這裡就可以重新封裝這個 api,比如統一成 $utils.showToast()
,這樣始終記住這一個就夠了。
可以封裝的功能包括:各種反饋彈窗、登入退出登出、支付、快取儲存、埋點函式、各框架提供的系統呼叫方法等。
把常用的重新封一遍再用,可以進一步磨平差異,減輕記憶負擔。
我的分享到此完畢,感謝閱讀,謝謝~