博主的開發及調試環境是 macOS 10.13.4 + Chrome/65.0.3325.181 + honorV9 EMUI8.0.0(Android8.0.0)
本文適合有一定前端開發經驗的小伙伴(有一定經驗看原文檔太累贅了,而且環境配置部分原文寫的太零碎了),最后總結了一些開發過程中遇到的坑。附文檔鏈接:https://doc.quickapp.cn/
本文沒有提到的部分和正常前端開發保持一致,也可能是我還沒有遇到的坑。。。
注冊賬號
首先你需要一個手機廠商對應開發者賬號和快應用賬號
由于博主的手機是華為,就在華為官網注冊一個個人開發者賬號就好啦,這個部分就不具體展開了。相關地址快應用也給我提供了一份列表和指南。值得說明的是,這個賬號是需要實名制的,有上傳身份證照片和個人照片審核的,審核需要1-2個工作日(華為使用芝麻信用認證可以即即刻生效,不知道其他廠家什么情況)。
然后打開快應用官網 https://www.quickapp.cn/, 點擊右上角的注冊,注冊一個快應用賬號,這個部分很簡單,也不展開了。
登陸以后我們可以看到導航欄上多出來一個開發者中心標簽,點擊進去,選擇【廠商賬號綁定】選項卡,選擇你的手機品牌方標簽進行綁定即可,目前小米、華為、金立、魅族、努比亞、OPPO 和 VIVO 都已經可以綁定了,而中興、聯想和一加還不能綁定。該綁定過程同樣需要1-2個工作日審核。
安裝相關軟件和工具
開發工具
首先你需要安裝 node v6.11.3 這是快應用官方推薦的版本
注意:不要使用 v8.0. 這個版本內部 ZipStream 實現與 node-archive 包不兼容,會引起報錯*
如果你已經使用了 node 高版本,可以安裝 nvm 管理 node 版本(如果你是第一次安裝 node 可以直接安裝 v6 版本,跳過該步驟)。
安裝nvm, 注意不要使用 brew 安裝,因為 curl 安裝不需要手動配置 .bashrc :
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
然后安裝對應版本node:
nvm install v6.11.3
檢查當前使用 node 版本:
nvm current
此時應該已經是我們需要的版本了,如果不是,可以手動切換。查看已安裝的 node 版本,和切換到已安裝的版本:
nvm ls # 查看已安裝版本
nvm use v6.11.3 # 使用已安裝版本
更多 nvm 用法直接輸入:
nvm --help
到這里,我們繼續快應用開發,全局安裝腳手架:
npm install -g hap-toolkit
檢測是否安裝成功:
hap -V
調試工具
chrome 的 devTools 肯定是必不可少的。除此之外我們需要在手機安裝一下兩個應用:快應用調試器(左),快應用預覽平臺(右)
如果你不安裝【快應用預覽平臺】,那么【快應用調試器】中的按鈕都是不可點擊的。而【快應用預覽平臺】里面其實啥也看不到,就是一個供快應用工作的殼。完整安裝好以后【快應用調試器】如下圖。
當然官方也給了一份 源碼, 方便大家熟悉生命周期,樣式,自定義組件,事件傳遞,組件使用。注意:下載后請記得操作:hap update --force
,增加編譯支持。
最后 adb 安裝(Homebrew):
brew cask install android-platform-tools
檢測是否安裝成功:
adb devices
Demo
項目生成
我們利用腳手架新建一個項目, 并且進入該項目, init 過程中需要輸入項目名稱:
hap init demo && cd demo
注意:之后的所有操作都在這個目錄下面
這是 demo 目錄結構
├── sign #rpk包簽名模塊
│ └── debug #調試環境
│ ├── certificate.pem #證書文件
│ └── private.pem #私鑰文件
├── src
│ ├── Common #公用的資源和組件文件
│ │ └── logo.png #應用圖標
│ ├── Demo #頁面目錄
│ | └── index.ux #頁面文件,可自定義頁面名稱
│ ├── app.ux #APP文件,可引入公共腳本,暴露公共數據和方法等
│ └── manifest.json #項目配置文件,配置應用圖標、頁面路由等
└── package.json #定義項目需要的各種模塊及配置信息
需要注意的是,sign 用來存放簽名模塊,sign/debug 中有用于調試的證書的私鑰,但debug簽名由于是公開的,安全性無法保證。在 release 發布之前一定要添加 release 目錄并且寫入對應的證書和私鑰:
openssl req -newkey rsa:2048 -nodes -keyout private.pem -x509 -days 3650 -out certificate.pem
mkdir sign/release && mv *.pem ./sign/release/
安裝相關依賴:
npm install
如果上面的安裝很慢,可以使用淘寶的資源:
npm install --registry=https://registry.npm.taobao.org
腳手架已經提供很多運行方式:
npm run release # 發布程序包,在 /dist/.signed.rpk,注意需要使用 release 簽名模塊
npm run build # 生成 build 和 dist 兩個目錄。前者是臨時產出,后者是最終產出
npm run watch # 文件保存時自動編譯和調試
調試方法
項目已和產生了 rpk 包,在做好之前的準備工作已后,運行:
npm run server # 當然,你可以通過 --port XXXX 指定端口,默認12306
此時,會在控制臺和 http://localhost:12306 得到一個二維碼,利用【快應用調試器】中的掃碼安裝,即可在手機上看到效果了。
此時你退出預覽界面,點擊【快應用調試器】中的開始調試,會同步在 chrome Devtool 中打開調試窗口,原理同在 chrome://inspect 中使用的遠程調試功能,如下圖:
調試可以采用一下三種方式:
npm run build # 手動編譯 + 手動刷新
npm run build && npm run notify # 手動編譯 + 自動刷新
npm run watch # 自動編譯 + 自動刷新
注意:使用遠程調試請確保手機與PC在同一局域網
開發
-
IDE / Code Editor
- VS Code: 搜索 Hap Extension 安裝插件即可
- webStorm: 可以通過 html 關聯 '.ux' 文件
- sublime: 選擇 html 高亮即可
- Android Studio: 使用 Android Monitor 看 console
-
console
為了正常使用 console.log 修改
src/manifest.json
中的 config 如下:{ "config": { "logLevel": "debug" } }
console 僅支持 info, log, warn, error, debug 方法。
-
LESS 支持
- 安裝 less、less-loader
- 在 style 標簽上添加
lang="less"
屬性即可
-
Async Function 支持
- 安裝 babel-runtime
- 將 babel 注入項目全局
/* app.ux 文件(如果沒有自己在 Common 里建一個)*/ <script> const global = Object.getPrototypeOf(global) || global global.regeneratorRuntime = require ('babel-runtime/regenerator') // else code... </script>
目錄結構 與 manifest
目錄結構
根目錄下的 sign 文件上文已經提到過,其他文件目錄不再贅述,因為前端項目大多如此,這里僅僅說 src 目錄:
src
├── manifest.json # 配置文件
├── app.ux # 入口文件
├── Page1 # 頁面1
│ ├── page1.ux
├── Page2 # 頁面2
│ ├── page2.ux
└── Common # 公共頁面和資源
├── ComponentA.ux
├── ComponentB.ux
└── xxx.png
manifest
manifest
屬性 | 類型 | 默認值 | 必填 | 描述 |
---|---|---|---|---|
package | String | - | 是 | 應用包名,確認與原生應用的包名不一致,推薦采用com.company.module的格式,如:com.example.demo |
name | String | - | 是 | 應用名稱,6個漢字以內,與應用商店保存的名稱一致,用于在桌面圖標、彈窗等處顯示應用名稱 |
icon | String | - | 是 | 應用圖標,提供192x192大小的即可 |
versionName | String | - | 否 | 應用版本名稱,如:"1.0" |
versionCode | Integer | - | 是 | 應用版本號,從1自增,推薦每次重新上傳包時versionCode+1 |
minPlatformVersion | Integer | - | 否 | 支持的最小平臺版本號,兼容性檢查,避免上線后在低版本平臺運行并導致不兼容;如果不填按照內測版本處理 |
features | Array | - | 否 | 接口列表,絕大部分接口都需要在這里聲明,否則不能調用,詳見每個接口的文檔說明 |
config | Object | - | 是 | 系統配置信息,詳見下面說明 |
router | Object | - | 是 | 路由信息,詳見下面說明 |
display | Object | - | 否 | UI顯示相關配置,詳見下面說明 |
config
用于定義系統配置和全局數據。
屬性 | 類型 | 默認值 | 描述 |
---|---|---|---|
logLevel | String | log | 打印日志等級,分為off,error,warn,info,log,debug |
designWidth | Integer | 750 | 頁面設計基準寬度,根據實際設備寬度來縮放元素大小 |
data | Object | - | 全局數據對象,屬性名不能以$或_開頭,在頁面中可通過this進行訪問;如果全局數據屬性與頁面的數據屬性重名,則頁面初始化時,全局數據會覆蓋頁面中對應的屬性值 |
router
用于定義頁面的組成和相關配置信息,如果頁面沒有配置路由信息,則在編譯打包時跳過。
屬性 | 類型 | 默認值 | 描述 |
---|---|---|---|
entry | String | - | 首頁名稱 |
pages | Object | - | 頁面配置列表,key值為頁面名稱(對應頁面目錄名,例如Hello對應'Hello'目錄),value為頁面詳細配置page,詳見下面說明 |
router.page
用于定義單個頁面路由信息。
屬性 | 類型 | 默認值 | 必填 | 描述 |
---|---|---|---|---|
component | String | - | 是 | 頁面對應的組件名,與ux文件名保持一致,例如'hello' 對應 'hello.ux' |
path | String | /<頁面名稱> | 否 | 頁面路徑,例如“/user”,不填則默認為/<頁面名稱>。path必須唯一,不能和其他page的path相同。下面page的path因為缺失,會被設置為“/Index”:"Index": {"component": "index"}
|
filter | Object | - | 否 | 聲明頁面可以處理某種請求 |
router.page.filter
聲明頁面可以處理某種請求,頁面可以從$page獲取打開頁面的參數。filter的結構如下:
"filter": {
"<action>": {
"uri": "<pattern>"
}
}
屬性 | 類型 | 默認值 | 必填 | 描述 |
---|---|---|---|---|
action | String | - | 是 | 請求的動作,目前僅支持view這一種 |
uri | Pattern | - | 是 | 請求的數據的匹配規則。必須是正則表達式。如https?://.* 可以匹配所有http和https類型的網址。 |
display
用于定義與UI顯示相關的配置。
屬性 | 類型 | 默認值 | 描述 |
---|---|---|---|
backgroundColor | String | #ffffff | 窗口背景顏色 |
fullScreen | Boolean | false | 是否是全屏模式,默認不會同時作用于titleBar,titleBar需要繼續通過titleBar控制 |
titleBar | Boolean | true | 是否顯示titleBar |
titleBarBackgroundColor | String | - | 標題欄背景色 |
titleBarTextColor | String | - | 標題欄文字顏色 |
titleBarText | String | - | 標題欄文字(也可通過頁面跳轉傳遞參數(titleBarText)設置) |
menu | Boolean | false | 是否顯示標題欄右上角菜單按鈕 |
pages | Object | - | 各個頁面的顯示樣式,key為頁面名(與路由中的頁面名保持一致),value為窗口顯示樣式,頁面樣式覆蓋default樣式。 |
template 結構
<!-- temp.ux -->
<import name="hint" src="./hint-modal"></import> <!-- 引入外部模板 -->
<import src="./table"></import> <!-- 引入外部模板 -->
<template>
<div class="container">
<div class="mod-header">
<text class="mod-title" style="color: red; margin: 10px;">{{title}}</text> <!-- 行內樣式 -->
<text class="mod-detail" onclick="showDetail">?</text> <!-- 無參事件綁定 -->
</div>
<div class="mod-content">
<!-- block 用來表示邏輯,不渲染 -->
<block for="totalData"> <!-- for 循環遍歷數組 $idx, $item 分別為數組的索引和值-->
<!-- 事件綁定 -->
<div onclick="onTabClick($idx)" class="item {{tabIndex === $idx && 'active'}}"> <!-- 支持簡單表達式 -->
<text class="{{tabIndex === $idx && 'text-active'}}">{{($item || {}).name}}</text>
<text class="{{tabIndex === $idx && 'text-active'}}">{{($item || {}).value}}</text> <!-- 布爾值、null、undefined、'' 不渲染,其余包括 falsy 值一律渲染 -->
</div>
</block>
</div>
<image class="mod-like" if="{{isLike}}" /> <!-- 支持if elif else, 必須是相鄰節點 -->
<image class="mod-dislike" else />
<table data={{dataList}}></table> <!-- 傳入屬性值,使用外部模板-->
<hint show="{{isHintShown}}">
This is children of hint templete.
</hint> <!-- 使用外部模板 -->
<!-- if 和 show 的區別:if 為 false 分支的節點不會渲染進 DOM 樹,而 show 為 false 的節點會渲染,只是 display: none; -->
</div>
</template>
<style lang="less" src="./lessFile.less"></style> <!-- 引入外部 CSS/LESS -->
<style lang="less">
/* 引入外部 CSS/LESS */
@import '../Common/global.less';
.container{
/* 定義樣式,less 支持 */
}
</style>
<script>
import fetch from "@system.fetch" // 引入系統 js
import conf from './globalConf'; // 引入外部 js
export default {
props: ['title', 'dataList'], // 傳入屬性:必須字母開頭,全小寫、數字和 `-` ,不能保留字和函數,不能以符號開頭
public: {
// 定義變量,會被 props 和內部請求覆蓋
},
private: {
// 定義變量,不會被 props 覆蓋
},
protected: {
// 定義變量,不會被 props 覆蓋, 但會被內部請求覆蓋(獲得通過 a 標簽和 router 傳遞的參數)
}
data :{ // data 不能和 public、private、protected 一起使用,data 也可以是 function(返回 data 對象,onInit之前執行)
// 定義變量:不能保留字和函數,不能以符號開頭
totalData: [{name: 'a',value: 97},{name: 'b',value: 98}];
// 定義變量,會被 props 覆蓋
},
onTabClick(index){ // 內部事件定義
console.log(index);
},
events: {
onIDChange(){
// 外部事件定義
}
}
}
</script>
<!-- hint.ux -->
<template>
<text><slot></slot></text> <!-- slot: 獲取該數據的引用的 children, 該例中即:This is children of hint templete. -->
</template>
開發基礎
保留字
除了傳統保留字,添加了 show tid 等;
生命周期
頁面生命周期
屬性 | 類型 | 參數 | 返回值 | 描述 | 觸發時機 |
---|---|---|---|---|---|
onInit | Function | 無 | 無 | 監聽頁面初始化 | 當頁面完成初始化時調用,只觸發一次 |
onReady | Function | 無 | 無 | 監聽頁面創建完成 | 當頁面完成創建可以顯示時觸發,只觸發一次 |
onShow | Function | 無 | 無 | 監聽頁面顯示 | 當進入頁面時觸發 |
onHide | Function | 無 | 無 | 監聽頁面隱藏 | 當頁面跳轉離開時觸發 |
onDestroy | Function | 無 | 無 | 監聽頁面退出 | 當頁面跳轉離開(不進入導航棧)時觸發 |
onBackPress | Function | 無 | Boolean | 監聽返回按鈕動作 | 當用戶點擊返回按鈕時觸發。返回true表示頁面自己處理返回邏輯,返回false表示使用默認的返回邏輯,不返回值會作為false處理 |
onMenuPress | Function | 無 | 無 | 監聽菜單按鈕動作 | 當用戶點擊菜單按鈕時觸發 |
A頁面的生命周期接口的調用順序:
- 打開頁面A:onInit() -> onReady() -> onShow()
- 在頁面A打開頁面B:onHide()
- 從頁面B返回頁面A:onShow()
- A頁面返回:onBackPress() -> onHide() -> onDestroy()
應用生命周期
屬性 | 類型 | 參數 | 返回值 | 描述 | 觸發時機 |
---|---|---|---|---|---|
onCreate | Function | 無 | 無 | 監聽應用創建 | 當應用創建時調用 |
onDestroy | Function | 無 | 無 | 監聽應用銷毀 | 當應用銷毀時觸發 |
預置對象
全局對象 (通過 this 訪問)
的屬性 | 類型 | 參數 | 描述 |
---|---|---|---|
$app | Object | - | 應用對象 |
|
Object | - | 獲取在app.ux中暴露的對象 |
|
Object | - | 獲取在manifest.json的config.data中聲明的全局數據 |
$page | Object | - | 頁面對象 |
$page.action | String | - | 獲取打開當前頁面的action。僅在當前頁面是通過filter匹配的方式打開時有效,否則為undefined。參見manifest |
$page.uri | String | - | 獲取打開當前頁面的uri。僅在當前頁面是通過filter匹配的方式打開時有效,否則為undefined。參見manifest |
$page.setTitleBar | Function | Object* | - |
$valid | Boolean | - | 頁面對象是否有效 |
$visible | Boolean | - | 頁面是否處于用戶可見狀態 |
* this.$page.setTitleBar 參數屬性包括:
{
text: 'Hello QuickApp', //標題欄文字
textColor: '#ffff', //文字顏色
backgroundColor: '#434343', //背景顏色
backgroundOpacity: '0.8', //背景透明度
menu: false, //是否在標題欄右上角顯示菜單按鈕 | 設置當前
}
屬性 | 類型 | 參數 | 描述 |
---|---|---|---|
$element | Function | id: String | 獲取指定id的組件dom對象,如果沒有指定id,則返回根組件dom對象用法:this.$element('xxx') 獲取id為xxx的組件實例對象 this.$element() 獲取根組件實例對象 |
$root | Function | 無 | 獲取頂層ViewModel |
$parent | Function | 無 | 獲取父親ViewModel |
$child | Function | id: String | 獲取指定id的自定義組件的ViewModel用法:this.$child('xxx') 獲取id為xxx的div組件ViewModel |
$vm deprecated
|
Function | id: String | 請使用上面this.$child('xxx')替代 |
$rootElement deprecated
|
Function | 無 | 請使用上面this.$element()替代 |
$forceUpdate | Function | 無 | 強制頁面刷新 |
公共屬性 | 類型 | 參數 | 描述 |
---|---|---|---|
$set | Function | key: String<br />value: Any | 添加數據屬性,必須在onInit函數中使用,用法:this.$set('key',value)
|
$delete | Function | key: String | 刪除數據屬性,如果在onInit函數中使用,用法:this.$delete('key')
|
元素屬性/方法 | 類型 | 參數 | 描述 |
---|---|---|---|
$set | Function | key: String<br />value: Any | 添加數據屬性,用法:this.$vm('id').$set('key',value)
|
$delete | Function | key: String | 刪除數據屬性,用法:this.$vm('id').$delete('key')
|
$on | Function | eventName: String handler: Function |
在當前頁面注冊監聽事件, 可監聽$emit() 、 $dispatch() 、 $broadcast() 等觸發的自定義事件,不能用于注冊組件節點的事件響應 |
$off | Function | eventName: String handler: Function |
移除事件監聽,參數 fnHandler 為可選,傳遞僅移除指定的響應函數,不傳遞則移除此事件的所有監聽 |
$emit | Function | eventName: String data: Object |
觸發當前實例監聽事件函數,與 $on() 配合使用 |
* 注意,獲取元素應該在頁面已渲染后,如 onReady 事件中或 onReady 事件執行完以后。
頁面設計
- 布局和尺寸
- 采用 border-box 模型且不支持 box-sizing 屬性
- 設計稿1px / 設計稿基準寬度 = 框架樣式1px / 項目配置基準寬度(項目配置基準寬度:
/src/manifest.json
中config.designWidth
的值,默認750)
- CSS
- 可以使用內聯樣式、tag選擇器、class選擇器、id選擇器來為組件設置樣式
- 僅可以使用并列選擇、后代選擇器、子代選擇器
- 支持@import引入外部樣式、內聯樣式、行內樣式
- 顏色值不支持縮寫,偽類支持不完全(支持
:disabled
,:checked
,:focus
等)
通用
- 通用事件:click, longpress, focus, blur, appear(組件出現),disappear(組件消失),swipe(快速滑動,參數direction:[left|right|up|down])
- 通用屬性: id, class, style, if, elif, else, for, show, disabled 等;
- 通用樣式:width, height, padding, padding-, margin, margin-, border, border-style, border-width, border-color, border--color, border--width, border-radius, border---radius, background-color, background-size, background-image(僅本地圖片), background-repeat, opacity, display(flex|none), flex, flex-grow, flex-shrick, flex-basis, position(none|fix), linear-gradient, repeating-inear-gradient, transform-origin, animation, animation-name, animation-delay, animation-duration, animation-iteration-count, animation-timing-function, animation-fill-mode, @key-frames(background-color|opacity|width|height|transform), transform(translate|translateX|translateY|rotate|rotateX|rotateY|scale|scaleX|scaleY)(以上代表枚舉[left|right|top|bottom], 具體和 css 一致。注:縮寫形式和展開形式不要同時使用*)
組件
默認支持通用事件、屬性和樣式
<text>
、<a>
、<span>
、<label>
組件為文本容器組件,其它組件不能直接放置文本內容
-
<div>
: 和 HTML 一樣- 支持樣式 flex-direction, flex-wrap, justify-content, align-items, align-content
-
<popup>
: 氣泡框- 支持屬性 target 和 placement
- 支持樣式 mask-color
- 支持事件 visibilitychange
- 自組件只能是
<text>
-
<refresh>
: 下拉刷新- 支持屬性 offset 和 refreshing
- 支持樣式 background-color 和 progress-color
- 支持事件 refresh
-
<richtext>
: 富文本編輯器- 支持屬性 type(值為 html)
- 支持div樣式, height 無效
- 不支持子組件
-
<stack>
: 子組件排列方式為層疊排列,每個直接子組件按照先后順序依次堆疊,覆蓋前一個子組件- 支持div樣式
-
<swiper>
: 輪播視圖容器- 支持屬性 index, interval, autoplay 和 indicator(是否顯示indicator)
- 支持樣式 indicator-color, indicator-selected-color 和 indicator-size
- 支持事件 change
- 支持方法 swipeTo(index)
-
<tabs>
: 選項卡- 支持屬性 index
- 支持事件 change
- 子組件僅支持最多一個<tab-bar>和最多一個<tab-content>
-
<tab-bar>
: 用來展示tab的標簽區,子組件排列方式為橫向排列- 支持屬性 mode(scrollable|fix)
- 支持樣式 height
- 支持事件 visibilitychange
-
<tab-content>
: 用來展示tab的內容區,高度默認充滿tabs剩余空間,子組件排列方式為橫向排列- 支持屬性 target 和 placement
- 支持樣式 mask-color
- 支持事件 visibilitychange
-
<list>
: 開發者在頁面中實現長列表或者屏幕滾動等效果時,習慣使用div組件做循環遍歷- 子組件必須是
<list-item>
; - 支持屬性 scrollpage,默認關閉,標志是否將頂部頁面中非
<list>
的元素隨<list>
一起滾動。開啟 scrollpage 會降低<list>
渲染性能 - 組件的性能優化分為: 精簡 DOM 層級、復用
<list-item>
、細粒度劃分<list-item>
、關閉 scrollpage 四個方面 - 支持 flex-direction 和 column
- 具有方法scrollTo(num)和事件scroll, scrollBottom, scrollTop
- 子組件必須是
-
<list-item>
list 的子元素- 的子組件可以是任何標簽或除
<list>
以外的組件 - 有一個屬性 type,type 值相同的
<list-item>
后代 DOM 必須一模一樣,如果不一樣,請使用不同的 type 值。type 不能為空! - 支持
<div>
樣式和 column-span,不支持 position
- 的子組件可以是任何標簽或除
-
<a>
: 鏈接- 支持屬性 href
- href 屬性值可根據路由配置
- href還支持http和https開頭的網址,點擊后會打開webview加載網頁
- href還可以通過“?param1=value1”的方式添加參數,參數可以在頁面中通過
this.param1
的方式使用 - 子組件僅支持<span>
- 僅支持 `text
- 支持 sms, tel, mailto
- 支持樣式 lines, color, font-style, font-weight(normal|bold),text-decoration, text-align, line-height, text-overflow
-
<image>
: 圖片- 支持屬性 src 和 alt
- 支持樣式 resize-mode(cover|contain|stretch|center)
- 不支持子組件
-
<process>
: 進度條- 支持屬性 percent 和 type(horizontal|circular)
- 支持樣式 color 和 stroke-width
- 支持事件 visibilitychange
- 不支持子組件
-
<rating>
: 星級評分- 支持屬性 numstars(總數), stepsize(步長), indicator(是否可操作)和 rating(值)
- 支持樣式 star-background, star-secondary, star-foreground(三種狀態的圖片)
- 支持事件 change,不支持click、longpress事件
- 不支持子組件
-
<span>
: 格式化的文本- 只能作為
<text>
與<a>
的子組件 - 不支持 show 和 disabled 屬性
- 支持樣式 color, font-size, font-style, font-weight(normal|bold),text-decoration
- 不支持任何事件
- 不支持子組件
- 只能作為
-
<text>
: 文本內容寫在標簽內容區,支持轉義字符""- 僅支持
<a>
與<span>
子組件 - 支持樣式 lines, color, font-style, font-weight(normal|bold),text-decoration, text-align, line-height, text-overflow
- 僅支持
-
<input>
: 接收用戶的輸入- 不支持子組件
- 支持屬性 type(button|checkbox|radio|text|email|date|time|number|password), name, value, checked 和 placeholder
- 支持樣式 color, placeholder-color, width, height 和 font-size
- 支持事件 change
- 支持方法 focus()
-
<label>
: 為input、textarea組件定義標注- 不支持子組件
- 支持屬性 target
- 支持樣式 lines, color, font-style, font-weight(normal|bold),text-decoration, text-align, line-height, text-overflow
- 不支持事件
-
<option>
:<select>
的子組件,用來展示下拉選擇具體項目- 不支持子組件
- 支持屬性 value 和 selected
- 不支持事件
-
<picker>
: 滾動選擇器,目前支持三種選擇器,普通選擇器,日期選擇器,時間選擇器。默認為普通選擇器。- 支持子組件
- 支持屬性 type(text|date|time), range, start, end, value 和 selected
- 不支持 click 事件, 支持 change 事件
- 支持方法 show()
-
<select>
: 下拉菜單- 僅支持<option>子組件
- 不支持 click 事件, 支持 change 事件
-
<slider>
: 滑動選擇器- 不支持子組件
- 支持屬性 min, max, value 和 step
- 支持樣式 color, selected-color, padding 僅支持 left 和 right
- 支持事件 change
-
<switch>
: 開關選擇- 不支持子組件
- 支持屬性 checked
- 支持事件 change
-
<textarea>
: 接收用戶的輸入- 不支持子組件
- 支持屬性 placeholder
- 支持樣式 color, placeholder-color 和 font-size
- 支持事件 change
- 支持方法 focus()
-
<video>
: 視頻播放器- 支持屬性 src, poster 和 autoplay
- 支持事件 prepared, start, pause, finish, error, seeking, seeked, timeupdate 和 fullscreenchange
- 支持方法 start(), pause(), setCurrentTime(seconds), requestFullscreen() 和 exitFullscreen()
-
<web>
: 用于顯示在線的html頁面- 必須聲明"打開網頁"接口,否則會提示缺乏權限。
- 支持屬性 src, src 值為 Deeplink, 參考下文 Deeplink 部分
- 支持樣式 mask-color
- 支持事件 titlereceive, pagestart, pagefinish 和 error
- 支持方法 reload(), forward(), back(), canForward(callback), canBack(callback)
接口
以下接口通過
import app from '@system.app'
或require('@system.app')
方式引入
接口申明在 manifest 文件的 features 中,除了@system.app
使用前以外都需要申明。
-
@system.app
-
getInfo()
, 得到應用名稱、版本名稱、版本號、log級別,三級來源
-
-
@system.share
- 內置分享,接口聲明:
{"name": "system.share"}
-
share({type: MIME Type, data:String/URL/FileList, success, fail, cancel, complete})
: 分享調用
-
- 第三方分享,接口聲明:
{"name": "service.share","params": {"appSign": "abcdefg...","qqKey":"1234567","wxKey":"wx1234","sinaKey":"1234"}}
- manifest 參數說明: appSign 簽名; qqKey QQ后臺ID; wxKey: 微信后臺ID, sinaKey 新浪后臺ID
-
getProvider()
: 獲取廠商信息 -
share({shareType:int, title, summary, targetUrl,imagePath, mediaUrl, success, fail, cancel, complete})
- 其中 shareType 默認圖文0,純文字1,純圖片2,音樂3,視頻4
cancel
- 其中 shareType 默認圖文0,純文字1,純圖片2,音樂3,視頻4
- 內置分享,接口聲明:
-
@system.router
- 接口聲明:
{"name": "system.router"}
-
push({url, params:Object})
: 跳轉url -
replace({url, params:Object})
: 跳轉url, 后退不會來 -
back()
: 后退 -
clear()
: 清空歷史棧 -
getLength()
: 獲取歷史棧長度 -
getState()
: 獲取當然頁面位置,名稱,路徑
- 接口聲明:
-
@system.prompt
- 接口聲明:
{"name": "system.prompt"}
-
showToast({message, duratuon:(0 or 1)})
: 顯示吐司 -
showDialog({title:, message:, buttons:[{text,color}], success({index}), fail, cancel, complete})
: 顯示對話框 -
showContextMenu({itemList:String[], itemColor:HexColor, success, fail, cancel, complete})
: 顯示上下文菜單
- 接口聲明:
-
@system.notification
- 接口聲明:
{"name": "system.notification"}
-
show({contentTitle, contentText, clickAction:{url}})
: 顯示通知
- 接口聲明:
-
@system.vibrator
- 接口聲明:
{"name": "system.vibrator"}
- vibrate(): 震動1s
- 接口聲明:
-
@system.webview
- 接口聲明:
{"name": "system.webview"}
-
loadUrl({url})
: 通過 webview 加載 url - 在webview打開的網頁中可以使用的api:
system.go(path)
: url 跳轉
- 接口聲明:
-
@system.request
- 接口聲明:
{"name": "system.request"}
-
upload({url, header:Object, method(POST|GET), files:{filename,name,url,type}[], data:{name,value}[], success({code,data,headers}), fail, complete})
: 上傳 -
download({url, header:Object, success({token}), fail, complete})
: 下載 -
onDownloadComplete({token, success({url}), fail({code}), complete})
: 監聽下載任務
- 接口聲明:
-
@system.fetch
- 接口聲明:
{"name": "system.fetch"}
-
fetch({url, header:Object, method(POST|GET), files:{filename,name,url,type}[], data:{name,value}[], success({code,data,headers}), fail, complete})
: 發起請求
- 接口聲明:
-
@system.storage
- 接口聲明:
{"name": "system.storage"}
-
get({key, default, success({data}), fail, complete})
: 獲取值 -
set({key, value, success, fail, complete})
: 存儲值 -
clear({success, fail, complete})
: 清空數據 -
delete({key, success, fail, complete})
: 刪除數據
- 接口聲明:
-
@system.file
- 接口聲明:
{"name": "system.file"}
-
move({srcUri, dstUri, success, fail({code}), complete})
: 移動文件 -
copy({srcUri, dstUri, success, fail({code}), complete})
: 復制文件 -
list({uri, success(fileList:{uil,list,lastModifiedTime}[]), fail({code}), complete})
: 獲取目錄下文件列表 -
get({uri, success({uil,list,lastModifiedTime}), fail({code}), complete})
: 獲取文件信息 -
delete({uri, success, fail(code**), complete})
: 獲取文件信息
- 接口聲明:
-
@system.barcode
(需要用戶授權)- 接口聲明:
{"name": "system.barcode"}
-
scan({success({result}), fail(code:201用戶拒絕), cancel, complete})
: 掃描二維碼
- 接口聲明:
-
@system.sensor
- 接口聲明:
{"name": "system.sensor"}
-
subscribeAccelerometer({callback(x,y,c)})
: 獲取重力感應數據 -
unsubscribeAccelerometer()
: 停止獲取重力感應數據 -
subscribeCompass({callback(direction)})
: 獲取羅盤數據 -
unsubscribeCompass()
: 停止獲取羅盤數據 -
subscribeProximity({callback(distance)
}): 獲取距離感應數據 -
unsubscribeProximity()
: 停止獲取距離感應數據 -
subscribeLight({callback(intensity)})
: 獲取光線感應數據 -
unsubscribeLight()
: 停止獲取光線感應數據
- 接口聲明:
-
@system.clipboard
- 接口聲明:
{"name": "system.clipboard"}
-
set({text, success, fail, complete})
: 寫入 -
get({success({text}), fail, complete})
: 讀取
- 接口聲明:
-
@system.geolocation
(需要用戶授權)- 接口聲明:
{"name": "system.geolocation"}
-
getLocation({timeout, success({longitude, latitude}), fail, complete})
: 獲取地理位置 -
subscribe({callback(longitude, latitude), fail})
: 監聽用戶位置 -
unsubscribe()
: 取消監聽用戶位置
- 接口聲明:
-
@system.shortcut
(需要用戶授權)- 接口聲明:
{"name": "system.shortcut"}
-
hasInstalled({success, fail, complete}
): 是否已創建桌面圖標 -
install({success, fail, complete})
: 創建桌面圖標
- 接口聲明:
-
@system.calandar
(需要用戶授權)- 接口聲明:
{"name": "system.calandar"}
-
insert({title, description, startDate:number, endDate:number, timezone:string, allDay:boolean是否整天, rrule:string重復規則, remindMinutes:number[]提前提醒時間, organizer: string, success, fail, cancel})
: 插入日歷事件
- 接口聲明:
-
@system.network
- 接口聲明:
{"name": "system.network"}
-
getType({success(metered是否按流量計費, type網絡類型), fail, complete})
: 獲取網絡類型 -
subscribe({callback(metered, type), fail})
: 監聽網絡情況 -
unsubscribe()
: 取消監聽網絡情況
- 接口聲明:
-
@system.device
(需要用戶授權)- 接口聲明:
{"name": "system.device"}
-
getInfo({success({brand, manufacturer, model, product, osType, osVersionName, osVersionCode, platformVersionName, platformVersionCode, language, region, screenWidth, screenHeight}), fail, complete})
: 獲取設備基本信息 -
getId({type(device|mac|user|advertising)[], success({device, mac, user, advertising}), fail, complete})
: 獲取設備標識 -
getDeviceId({success({deviceId}), fail, complete})
: 獲取設備ID -
getUserId({success({userId}), fail, complete})
: 獲取用戶ID -
getAdvertisingId({success({advertisingId}), fail, complete})
: 獲取廣告ID -
getTotalStorage({success({totalStorage}), fail, complete})
: 獲取總容量 -
getAvailableStorage({success({availableStorage})
, fail, complete}): 獲取可用容量 -
getCpuInfo({success({cpuInfo}), fail, complete})
: 獲取cpu信息
- 接口聲明:
-
@system.brightness
- 接口聲明:
{"name": "system.brightness"}
-
getValue({success({value}), fail, complete})
: 獲取屏幕亮度 -
setValue({value, success(value:0手動;1自動), fail, complete})
: 設置屏幕亮度 -
getMode({success(value:0手動;1自動), fail, complete})
: 獲取屏幕亮度模式 -
setMode({value, success, fail, complete})
: 設置屏幕亮度模式 1. 接口聲明:{"name": "system.volume"}
- 接口聲明:
-
@system.volume
- 接口聲明:
{"name": "system.volume"}
-
getMediaValue({success(value:0到1), fail, complete})
: 獲取音量 -
setMediaValue({value, success, fail, complete})
: 設置音量
- 接口聲明:
-
@system.battary
- 接口聲明:
{"name": "system.battary"}
-
getStatus({success(charging, level:0到1), fail, complete})
: 獲取當前電池狀態
- 接口聲明:
-
@system.package
- 接口聲明:
{"name": "system.package"}
-
hasInstalled({package包名, success(result:boolean), fail, complete})
: 判斷是否安裝了某個應用 -
install({package, success(result:boolean), fail, complete})
: 安裝應用 - 利用路由中的 push 操作打開應用
- 接口聲明:
-
@system.record
(需要用戶授權)- 接口聲明:
{"name": "system.record"}
-
start({success({url}), fail, complete})
: 開始錄音 -
record.stop()
: 停止錄音
- 接口聲明:
-
@system.cipher
- 接口聲明:
{"name": "system.cipher"}
-
rsa({action:encrypt|decrypt, text, key加密為公鑰|解密為私鑰, transformation補充項,success({text}), fail, complete})
: rsa 加密解密
- 接口聲明:
-
@system.media
(需要用戶授權)- 接口聲明:
{"name": "system.media"}
-
takePhoto({success({uri}), fail, complete, cancel})
: 拍照 -
takeVideo({success({uri}), fail, complete, cancel})
: 錄像 -
pickImage({success({uri}), fail, complete, cancel})
: 選擇圖片 -
pickVideo({success({uri}), fail, complete, cancel})
: 選擇視頻
- 接口聲明:
-
@system.image
- 接口聲明:
{"name": "system.image"}
-
getImageInfo({uri, success({uri, width, height, size}), fail, complete, cancel})
: 獲取圖片基礎信息 -
compressImage({uri, quality:1到100, ratio:number縮放比, format:圖片格式, success({uri, width, height, size}), fail, complete, cancel})
: 壓縮圖片 -
applyOperations({uri, operations:Object[](如下), quality, format, success({uri}), fail, complete, cancel}})
: 對圖片按順序執行編輯操作- 剪裁:
{action: 'crop', x, y, width, height}
- 縮放:
{action: 'scale', scaleX, scaleY}
- 旋轉:
{action: 'rotate', degree}
- 剪裁:
-
editImage({uri, success({uri}), fail, complete, cancel})
: 使用編輯器編輯圖片
- 接口聲明:
-
@system.audio
- 接口聲明:
{"name": "system.audio"}
-
play()
: 播放 -
pause()
: 暫停 - 屬性: src, currentTime, duration, autoplay, loop, volume, muted
- 事件: play, pause, loadeddata, ended, durationchange, error, timeupdate
- 接口聲明:
-
@system.push
- 接口聲明:
{"name": "system.push"}
-
getProvider()
: 獲取服務提供商 -
subscribe({success({regId}), fail, complete})
: 訂閱push -
unsubscribe()
: 取消訂閱push -
on({callback(messageId, data)})
: 添加push事件回調 -
off()
: 移除push事件回調
- 接口聲明:
-
@system.pay
- 接口聲明:
{"name": "system.pay"}
-
getProvider()
: 獲取服務提供商 -
pay({orderInfo:String, success({code, message, result}), fail({code, message}), complete})
: 付款
- 接口聲明:
-
@system.stats
- 接口聲明:
{"name": "system.stats"}
-
getProvider()
: 獲取服務提供商 -
recordCountEvent({category, key, map})
: 計數類型事件 -
recordCalculateEvent({category, key, value, map})
: 計算類型事件
- 接口聲明:
-
@system.account
- 接口聲明:
{"name": "system.account"}
-
getProvider()
: 獲取服務提供商 -
authorize({type:string(code|token), redirectUri, scope, state, success({state, code, accessToken, tokenType, expiresIn, scope}), fail, complete)
: 認證 -
getProfile({token, success({openid, id, unionid, nickname, avatar}), fail, complete})
: 獲取用戶認證信息
- 接口聲明:
-
@system.alipay
- 接口聲明:
{"name": "system.alipay"}
-
pay({orderInfo:string, callback})
: 支付 - 支付寶支付細節,請查看請求參數說明文檔
- 接口聲明:
-
@system.wxpay
- 接口聲明:
{"name": "service.wxpay", "params": {"package": "com.your.package", "sign": "abcdefg", "url": "http://your.domain/page"}}
- 兩種方式的 manifest 配置:
- app 原生:package: 包名,sign: 簽名
- web 方式:url:H5 url
-
getType()
: 返回調用方式(none|APP|MWEB) -
pay({prepayid, extra, success({prepayid,final_url}), fail(code**), complete})
: 支付- extra app 版參數如下
- app_id: 微信支付訂單中的app_id
- partner_id: 微信支付訂單中的partner_id
- package_value: 微信支付訂單中的package_value
- nonce_str: 微信支付訂單中的nonce_str
- time_stamp: 微信支付訂單中的time_stamp
- order_sign: 微信支付訂單中的order_sign
- extra app 版參數如下
- mweb_url: 在微信的支付服務器下單以后,微信返回的 MWEB_URL,在CP用于微信支付的h5頁面中,直接將mweb_url取出后跳轉過去即可,但這個做法并不是強制的,您也可以通過其他自定義鍵值向您自己的服務器換取MWEB_URL
- custome_key: 其他的自定義鍵值,cp可以根據需要增加其他自己認為需要的鍵名和鍵值
- extra app 版參數如下
- 微信支付細節,請參考微信網頁支付和微信app支付
- 接口聲明:
以上接口錯誤列表如下:
- 201 用戶拒絕
- 202 參數錯誤
- 204 超時
- 300 I/O錯誤
- 301 路徑不存在
- 900 簽名有誤
- 901 包名有誤
- 1000 應用未安裝|下載失敗|位置開關關閉
- 1001 url配置找不到|任務不存在
- 2001 內部錯誤
頁面切換和參數傳遞
傳遞方法1. <a>
標簽配合 queryString 傳遞參數, 這個和前端一致。
<a href="/src/home/index.html?key=2333">跳轉頁面</a>
傳遞方法2. 通過 router 接口:router.push(), router.replace(), 接受一個如下結構的對象,用法這個和前端 router 一致。
{
url: '/src/home/index.html',
params: { key: 2333 /* 需要傳遞的參數 */ }
}
接收方法:上述2種傳遞參數的方法,其接收方法一致,在接收參數頁面的 protected 對象中獲取即可(可設置默認值)
<script>
export default {
protected: {
key: 0 // 得到傳過來的 key: 2333, 0 為默認值
}
}
</script>
回傳參數:借助 this.data 實現,相當于綁定數據到全局了,這個不再舉例
頁面間通信
這個部分和 HTML5 中的同源頁面通信如出一轍。會利用到一個構造函數 new BroadcastChannel(string)
, 它接受一個字符串參數,作為實例的頻道名稱。它的實例具有以下屬性和方法:
名稱 | 類型 | 參數 | 描述 |
---|---|---|---|
name | String | - | 頻道名稱,區分不同的消息頻道(注意:不同頻道之間不可通信)。 |
postMessage | Function | Any: 消息內容 | 用于在當前頻道中廣播消息。 |
onmessage | Function | Event:消息對象 | 訂閱消息。在頻道中接收到廣播消息之后,會給所有訂閱者派發消息事件。 |
close | Function | - | 關閉當前的頻道。 |
其中 onmessage 事件有2個屬性(通過 event 對象訪問):
屬性 | 類型 | 描述 |
---|---|---|
type | String | "message" |
data | Any | 接收到的消息內容 |
由于和 HTML5 用法一樣,這里就不演示了。
組件通信
父子組件通信
父子組件使用見 template 部分
- 父組件到子組件
- 子組件通過 props 獲取父組件傳入的值,見上文 template 部分
- 通過 this.watch(props, callback) 監控傳入數據變化并調用回調函數
- 父組件通過
this.$broadcast()
完成事件觸發,子組件通過$on()
綁定事件并響應
- 子組件到父組件
- 父子組件傳對象類型屬于引用傳遞,可以直接修改父組件傳入對象改變父組件數據
- 子組件通過
this.$dispatch()
完成事件觸發,父組件通過$on()
綁定事件并響應 - 子組件通過
this.$emit()
觸發在節點上綁定的事件來執行父組件的方法
* 注:this.$broadcast()
、this.$emit()
和 this.$dispatch()
參數一致
* 注:觸發時傳遞參數,再接收時使用event.detail
來獲取參數
* 注:當傳遞結束后,可以調用event.stop()
來結束傳遞
Deeplink
配合<web>
標簽框架支持通過鏈接從外部打開應用,格式
http://hapjs.org/app/<package>/[path][?key=value]
https://hapjs.org/app/<package>/[path][?key=value]
hap://app/<package>/[path][?key=value]
參數說明:
- package: 應用包名,必選
- path: 應用內頁面的path,可選,默認為首頁
- key-value: 希望傳給頁面的參數,可選,可以有多個
從傳統網頁調起需引入以下腳本:
<script src='//statres.quickapp.cn/quickapp/js/routerinline.min.js'/>
提供方法:
- appRouter(packageName, pageName, params, confirm)
- packageName:應用的包名,和manifest.json中保持一致
- pageName:跳轉的頁面,對應于manifest.json中pages的path字段. 特殊的.如果傳入的是"/",則跳轉到path為"/"的頁面,如果無此頁面,則跳轉到首頁. 更多信息,請參見manifest中path字段的說明.
- params:攜帶參數,形式為{ param1: value1, param2: value2 }
- confirm:顯示給用戶的應用名稱,當不為空時,表示跳轉時需要用戶確認,當不傳或者為false時,表示無需用戶確認直接跳轉
- channelReady(callback)
- callback:檢測的回調函數,無論檢測到是否支持服務,都會執行回調函數。平臺支持服務則傳入實參true,否則傳入實參false
遇到的一些坑
- 自定義屬性名不能采用駝峰命名,否則值永遠是 undefined
- show 屬性并不好用,沒起什么作用
- 類似 onInit 等等函數是頁面生命周期,不是組件生命周期,不會因為組件狀態變化而執行
- display 類型只有 flex 和 none
- 子盒子不能將父盒子撐高
- 不遵循盒子模型,類似但不完全等同于 border-box,
- css選擇器在覆蓋樣式時候,不能采用后代選擇器寫法(初次定義樣式時可以),這樣子 box 樣式不會生效,因為性能問題,當前只支持 CSS 聲明的多個選擇器中最后一個規則的變更對DOM的更新,例如,下例中給 .tag 添加了 .active 后,只有邊框顏色會變,字的顏色不會變。
<style>
.tag{
/* 邊框樣式不支持縮寫 */
border-bottom-color: #cccccc; /* 顏色不支持縮寫 */
border-bottom-width: 2px;
text{
color: #666666;
}
}
.active{
border-bottom-color: #3333ff;
text{
color: #3333ff;
}
}
</style>