作者:餓了麼 顧誠
開篇也不扯那些沒用的,讓我們高效的開始教程。
在一切教程開始前
無論學習什麼語言、框架、庫,首先你要做的,就是登陸它的官網,認真閱讀它的入門手冊、文件等,這比任何《xx 分鐘從入門到精通》、《xx 深入淺出》都要靠譜得多,再加上現在程式設計體系的愈加完善,開發者越來越注重基礎設施的搭建,官網絕對是學習一樣東西的首先選擇。 所以,快應用現在的 官網是:https://www.quickapp.cn 文件是:https://doc.quickapp.cn 請認真閱讀文件。
在快應用的教程開始之前
快應用宣傳的一大優勢,就是對於 Web 前端開發者的低學習成本、快速上手。那麼它的這個優勢,其實是建立在你熟悉(有一定程度瞭解)類 Vuejs 的框架的前提上的。 它基本上是建立在 Vue 的體系上的,經過一定程度的改造、精簡,形成了快應用的開發體系。 本篇教程,也預設你對 Vue 已經有一定程度的瞭解,假如你還沒有完成這個前提,那麼先去了解一下 Vue 也不錯。 所以,讓我假設閱讀本文的你,是一名擁有 Vue 經驗的 Web 前端開發者,對新出的快應用有一定興趣,想要了解一下它,那麼,希望文章對你有所幫助。
教程前置準備
上文也說了,快應用的開發,對比的就是 Vue 的體系,所以,我選擇通過對比同樣實現目標的 APP 的 Vue 版本和快應用版本,來說明你要進行快應用開發需要準備和了解哪些東西。 首先,我選擇了人民群眾喜聞樂見的 HackerNews 作為實現目標,它提供了完善的 API,方便我們構建真實 APP,並且 Vue 的官方也有一個 Demo 版本的 HackerNews 原始碼,省去了我們不少工作。 所以我們直接選擇 https://github.com/vuejs/vue-hackernews 當前 master 分支作為 Vue 版本的程式碼,你們也可以自行 clone 檢視。
快應用專案初始化
請根據快應用官方文件的快速入門一節,準備好開發環境,在這裡只有一點提醒:假如你的手機還沒有直接支援快應用的執行環境(提示沒有執行環境),請安裝「快應用平臺預覽版」,通過它進行除錯。
開始
首先確認一下我們的工程結構
.
├── quickapp
│ ├── README.md
│ ├── build
│ ├── dist
│ ├── node_modules
│ ├── package-lock.json
│ ├── package.json
│ ├── sign
│ └── src
└── vue
├── LICENSE
├── README.md
├── index.html
├── node_modules
├── package.json
├── src
├── static
└── webpack.config.js
複製程式碼
就是這樣,快應用是通過 hap 工具直接初始化的工程,作為開發者,直接寫程式碼就完事了,我想你目前應該也不關心快應用的實現原理和內部細節。
1. 第一步:入口
Vue 專案的入口自然是 index.html 和 main.js,它的核心程式碼結構是這樣的:
src
├── components
├── filters
├── main.js
├── store
└── variables.styl
複製程式碼
好,看一下 main.js
import Vue from 'vue'
import Router from 'vue-router'
import { domain, fromNow } from './filters'
import App from './components/App.vue'
import NewsView from './components/NewsView.vue'
import ItemView from './components/ItemView.vue'
import UserView from './components/UserView.vue'
// install router
Vue.use(Router)
// register filters globally
Vue.filter('fromNow', fromNow)
Vue.filter('domain', domain)
// routing
var router = new Router()
router.map({
'/news/:page': {
component: NewsView
},
'/user/:id': {
component: UserView
},
'/item/:id': {
component: ItemView
}
})
router.beforeEach(function () {
window.scrollTo(0, 0)
})
router.redirect({
'*': '/news/1'
})
router.start(App, '#app')
複製程式碼
很簡單,做了幾件事情:
- 引入框架(Vue,VueRouter)
- 引入元件
- 定義 filters、路由
- 啟動應用
OK,那麼我們去快應用裡面看一下,快應用裡,一個 APP 的 入口,是 src/manifest.json
,一個 APP 的重要資訊就定義在這裡面,我們看一下
{
"package": "me.ele.hacknews",
"name": "quickapp-hackernews",
"versionName": "1.0.0",
"versionCode": "1",
"minPlatformVersion": "101",
"icon": "/Common/logo.png",
"features": [
{ "name": "system.prompt" },
{ "name": "system.router" },
{ "name": "system.shortcut" },
{ "name": "system.fetch" }
],
"permissions": [
{ "origin": "*" }
],
"config": {
"logLevel": "debug"
},
"router": {
"entry": "News",
"pages": {
"News": {
"component": "index"
},
"User": {
"component": "index"
},
"Item": {
"component": "index"
}
}
},
"display": {
"titleBarBackgroundColor": "#ff6600",
"titleBarTextColor": "#ffffff",
"menu": true,
"pages": {
"News": {
"titleBarText": "Hacker News | QuickApp Clone"
}
}
}
}
複製程式碼
當然,這和你剛初始化完成時候的配置肯定不一樣了,不過我只是改成了 HackerNews 的配置,結構並沒有改變,來看一下:
- 定義好包名(package)、應用名(name)、logo(logo)
- 定義需要用的系統介面(features),所以上文讓你認真看文件,呼叫系統介面都是需要提前宣告(你也不想使用者說你濫用許可權對吧),這裡我們需要router(路由)、fetch(網路請求)
- config.logLevel 先改成 debug 好了,輸出所有 log
- router 中定義好所有路由,entry 就是首頁,pages 和 component 對應好
- display 你可以先不管(不過也沒什麼難度就是了)
那麼對比 Vue 的啟動配置來說,因為快應用是執行在系統整合環境中的,所以 Vue 專案要求的引入框架、庫(路由)就都不需要了,多出了系統介面的提前宣告,按需宣告就可以了,這專案只需要最基本的路由、網路請求許可權就可以了。
路由這塊,請參考官方文件,稍微需要注意的就是 page 預設使用它的名稱資料夾作為它的元件所在位置。基本上也和 Vue 版本的路由對應的配置就可以了,需要注意的是路由引數不需要在這裡配置,而是在對應的元件內配置(作為元件外部傳入屬性)。
到這裡,你就已經完成了快應用專案的基礎配置,當然,現在是執行不起來的,你配置的頁面還沒有實現對應的元件,下面我們就把 Vue 的頁面元件改造成快應用的元件。
2. 改造 Vue-> QuickApp
看一下快應用版本的原始碼目錄結構
src
├── Common
├── Item
├── News
├── User
├── app.ux
├── filters
├── manifest.json
├── store
└── util.js
複製程式碼
一個頁面對應一個目錄,app.ux 是入口元件(現在不用管它),我們開始改造過程。
第一個頁面就是首頁(News),上改造前後對比圖,diff 圖左邊是 Vue 專案程式碼,右邊是快應用程式碼,我們來逐一分析:
template 部分
- 自定義元件引入,用特殊的 import 標籤引入,直接可以在 template 中使用
- 用 list 元件提高列表效能,就先把它當成 div 好了(想要進一步瞭解,請閱讀官方文件,list 優化一節)
- 快應用不支援 :before, :after 偽類,因此 loading 文字只能用一個單獨的元素並根據條件來展示了。
- 你也發現在快應用中:
- v-show -> show
- v-for -> for
- v-if -> if
- :property -> property="{{ }}"
- track-by -> tid
- $index -> $idx
基本上就是去掉了 Vue 特色,變成了通用單詞。
另外,大部分表示式使用時(除 for、tid 等),要寫在
{{ expression }}
中,需要注意一下。
- 文字寫在
text
元件內!(請認真閱讀文件),這和 Web 開發有很大區別,HTML 的體系中,基本是個標籤就能加文字,但是快應用中不行,需要繫結在text
元件內。文字寫在text
元件內!文字寫在text
元件內! - 沒有 filter,這個在某些情況下確實有些不方便,只能改造成函式了
$index | formatItemIndex
->formatItemIndex($idx)
。
完成以上步驟,你的 template 部分就基本改造完成了,對著手冊一一改造就可以了。
script 部分
這部分改動很少,快應用支援 ES2015 的絕大部分語法、特性,這裡有一個不好的地方,官方沒有詳細說明支援程度,可能會遇到支援性問題。
- 引入路由服務,因為需要手動跳轉(快應用也支援 href 跳轉,這裡只是為了演示),使用系統服務,就按照正常的引入專案模組的邏輯來進行就可以了。
- 不在 script 引入自定義元件。
- 生命週期,改個名字,常用的就是 onInit、onReady、onDestroy,顧名思義,不懂看文件。
- 方法,快應用的方法不需要定義在 methods 裡面,因為它的元件裡,沒那麼多其餘屬性,直接在元件物件第一層下定義方法就可以了,script 和 template 通用。因此我們把所有方法都從 methods 裡面搬了出來。
- filters,上文說了,快應用沒有 filter,就改造成普通方法好了(壞處是不能定義全域性 filter,每個元件都需要反覆引入 filter 方法,當然可以在 App 層面定義方法,不過不好管理)。
- 補上一個頁面跳轉的方法,可以看一下使用方式,就是普通的函式呼叫,uri + params
完成了以上步驟,你就基本完成了script 部分的改造,這裡有一個問題,Vuex 你不禁想問,Vuex 怎麼辦,上面我寫的那個 store,是 vuex 嗎?不是。 很遺憾,假如你依賴於 Vuex,你可能會遇到麻煩,我還沒有很好的辦法替代 Vuex,快應用支援全域性 data,支援 watch,但是並不足以替代 Vuex,上面的 store,並不是 Vuex,只是一個處理資料的服務,下文會說到。
style
style 部分看上去是最簡單,但其實是最麻煩的部分:
- style 僅支援部分 CSS 屬性
- 快應用使用 flex 進行佈局
- 快應用有預設的螢幕適配(750px),你寫的所有 px 單位,都會以 750px 為標準進行縮放適配,有優勢,也有缺點。
- 快應用有一些特有的屬性
- 快應用的選擇器支援比較有限
上面這些特點,需要你認真閱讀快應用文件的 style部分,以及各個元件的樣式部分,來了解情況,請一定要認真閱讀,你很容易用上了不支援的 CSS 特性。
我們這個 DEMO 專案的 style 比較簡單,Vue 專案用了 stylus,快應用顯然不支援,為了方便轉成了 CSS,不過快應用支援 Less CSS,也是不錯的選擇。
- 根據 flex 佈局做一些調整
- 把偽類改成了獨立元素
- 移除了不支援的屬性
- 移除不支援的偽類(hover 之類的)
- 適配一些不支援的縮寫語法
這可能是一個體驗很糟糕的過程,寫著名義上是 CSS 卻有那麼多不同的 style 程式碼,不過無論如何,我們總算是完成了 style 部分的改造。
改造小結
很明顯,通過以上對比,你會發現,快應用的程式碼體系,真的很像 Vue,但是又有那麼一些糟糕的區別。 還是那句話,如果你想要進行快應用的開發,請認真閱讀文件,磨刀不誤砍柴工。
元件之外
顯然我們的專案裡,一般不會只有元件這一種東西,還有一些 JavaScript 模組,比如上文的 store,這時候正文開始了 :)。
diff 圖左邊是 Vue 專案程式碼,右邊是快應用程式碼
what? firebase 庫? 講道理,這是一個 JavaScript 庫,應該可以在快應用環境中直接使用,但是實際上,不行。
firebase 庫依賴於很多瀏覽器(window)API,比如 XHR 請求,這時候,它就無法在快應用的體系中正常執行了。 這時候你陷入了一個兩難的抉擇,對 firebase 的庫進行魔改,或者自己造一個 firebase 庫。 這時候你可能就想放棄了,事實就是這麼殘酷,你會想,我做了這個事情我怎麼不去加入 firebase?
但是教程總是要繼續,好在我們這個專案真的很簡單,簡單到我不需要 firebase 的庫,也可以輕鬆相容原始碼,完成改造。
- 引入 fetch API(和瀏覽器中 Fetch api 有一定區別)
- 宣告 hackernews 的 firebase API host 地址
- 把原先的 firebase 方法
api.child
改造成直接的 fetch 呼叫
看上去好像也沒什麼問題,因為我們這裡的 firebase 呼叫足夠簡單,僅僅是請求資料而已。
- 像是 fetch 這樣的快應用系統介面,都是用 callback 回撥的形式實現的
- 快應用支援 Promise,因此我們可以輕鬆實現 Promise 相容,避免了業務層的改動
- 快應用也支援直接引入 Node 模組
萬幸,我們完成了 store 部分的改造。
教程的尾聲
然後其實也只剩下 Item、User 等元件了,依次完成改造。按照官方開發環境的說明
- npm run server
- 用手機安裝除錯工具(可能還需要平臺預覽版),掃描二維碼
- 檢視一下效果
預覽圖:
預覽視訊:
你要問了
Q: 為什麼這麼醜? A: 沒時間調整樣式,這是個 DEMO(側面反映,普通 CSS 不能完美地直接遷移到快應用內)
Q: 為什麼頁面載入這麼慢? A: 因為 firebase 的介面慢,並且介面是先請求 id 列表,然後逐一請求 item,最後合併返回,必然很慢,因為我們不能使用 firebase 庫。。。
Q: 你吹噓的那些快、輕量、原生完全沒體現出來! A: 確實,這個 DEMO 是在太簡單了,如果你有興趣,可以嘗試自己動手寫一個快應用 APP,一定可以直觀地感受到它和普通網頁應用的區別
Q: 我看完你的教程,覺得什麼都沒講?!還是不會寫! A: 在教程的一開始,我已經說過了,學習一樣東西,最好的方法當然是它的官網啦,其實現在快應用的快網已經非常完善了,從入門教程到手冊到效能提升建議到深入實踐,看完你一定有所收穫。
Talk is cheap, show me the code.