快应用开发快速上手及简明教程

博主的开发及调试环境是 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

    1. VS Code: 搜索 Hap Extension 安装插件即可
    2. webStorm: 可以通过 html 关联 '.ux' 文件
    3. sublime: 选择 html 高亮即可
    4. Android Studio: 使用 Android Monitor 看 console
  • console

    为了正常使用 console.log 修改 src/manifest.json 中的 config 如下:

    {
     "config": {
        "logLevel": "debug"
      }
    }

    console 仅支持 info, log, warn, error, debug 方法。

  • LESS 支持

    1. 安装 less、less-loader
    2. 在 style 标签上添加 lang="less" 属性即可
  • Async Function 支持

    1. 安装 babel-runtime
    2. 将 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

属性类型默认值必填描述
packageString-应用包名,确认与原生应用的包名不一致,推荐采用com.company.module的格式,如:com.example.demo
nameString-应用名称,6个汉字以内,与应用商店保存的名称一致,用于在桌面图标、弹窗等处显示应用名称
iconString-应用图标,提供192x192大小的即可
versionNameString-应用版本名称,如:"1.0"
versionCodeInteger-应用版本号,从1自增,推荐每次重新上传包时versionCode+1
minPlatformVersionInteger-支持的最小平台版本号,兼容性检查,避免上线后在低版本平台运行并导致不兼容;如果不填按照内测版本处理
featuresArray-接口列表,绝大部分接口都需要在这里声明,否则不能调用,详见每个接口的文档说明
configObject-系统配置信息,详见下面说明
routerObject-路由信息,详见下面说明
displayObject-UI显示相关配置,详见下面说明

config

用于定义系统配置和全局数据。

属性类型默认值描述
logLevelStringlog打印日志等级,分为off,error,warn,info,log,debug
designWidthInteger750页面设计基准宽度,根据实际设备宽度来缩放元素大小
dataObject-全局数据对象,属性名不能以$或_开头,在页面中可通过this进行访问;如果全局数据属性与页面的数据属性重名,则页面初始化时,全局数据会覆盖页面中对应的属性值

router

用于定义页面的组成和相关配置信息,如果页面没有配置路由信息,则在编译打包时跳过。

属性类型默认值描述
entryString-首页名称
pagesObject-页面配置列表,key值为页面名称(对应页面目录名,例如Hello对应'Hello'目录),value为页面详细配置page,详见下面说明

router.page

用于定义单个页面路由信息。

属性类型默认值必填描述
componentString-页面对应的组件名,与ux文件名保持一致,例如'hello' 对应 'hello.ux'
pathString/<页面名称>页面路径,例如“/user”,不填则默认为/<页面名称>。path必须唯一,不能和其他page的path相同。下面page的path因为缺失,会被设置为“/Index”:"Index": {"component": "index"}
filterObject-声明页面可以处理某种请求

router.page.filter

声明页面可以处理某种请求,页面可以从$page获取打开页面的参数。filter的结构如下:

"filter": {
  "<action>": {
    "uri": "<pattern>"
  }
}
属性类型默认值必填描述
actionString-请求的动作,目前仅支持view这一种
uriPattern-请求的数据的匹配规则。必须是正则表达式。如https?://.*可以匹配所有http和https类型的网址。

display

用于定义与UI显示相关的配置。

属性类型默认值描述
backgroundColorString#ffffff窗口背景颜色
fullScreenBooleanfalse是否是全屏模式,默认不会同时作用于titleBar,titleBar需要继续通过titleBar控制
titleBarBooleantrue是否显示titleBar
titleBarBackgroundColorString-标题栏背景色
titleBarTextColorString-标题栏文字颜色
titleBarTextString-标题栏文字(也可通过页面跳转传递参数(titleBarText)设置)
menuBooleanfalse是否显示标题栏右上角菜单按钮
pagesObject-各个页面的显示样式,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 等;

生命周期

页面生命周期

属性类型参数返回值描述触发时机
onInitFunction监听页面初始化当页面完成初始化时调用,只触发一次
onReadyFunction监听页面创建完成当页面完成创建可以显示时触发,只触发一次
onShowFunction监听页面显示当进入页面时触发
onHideFunction监听页面隐藏当页面跳转离开时触发
onDestroyFunction监听页面退出当页面跳转离开(不进入导航栈)时触发
onBackPressFunctionBoolean监听返回按钮动作当用户点击返回按钮时触发。返回true表示页面自己处理返回逻辑,返回false表示使用默认的返回逻辑,不返回值会作为false处理
onMenuPressFunction监听菜单按钮动作当用户点击菜单按钮时触发

A页面的生命周期接口的调用顺序:

  1. 打开页面A:onInit() -> onReady() -> onShow()
  2. 在页面A打开页面B:onHide()
  3. 从页面B返回页面A:onShow()
  4. A页面返回:onBackPress() -> onHide() -> onDestroy()

应用生命周期

属性类型参数返回值描述触发时机
onCreateFunction监听应用创建当应用创建时调用
onDestroyFunction监听应用销毁当应用销毁时触发

预置对象

全局对象 (通过 this 访问)

的属性类型参数描述
$appObject-应用对象
$app.$defObject-获取在app.ux中暴露的对象
$app.$dataObject-获取在manifest.json的config.data中声明的全局数据
$pageObject-页面对象
$page.actionString-获取打开当前页面的action。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined。参见manifest
$page.uriString-获取打开当前页面的uri。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined。参见manifest
$page.setTitleBarFunctionObject*-
$validBoolean-页面对象是否有效
$visibleBoolean-页面是否处于用户可见状态

* this.$page.setTitleBar 参数属性包括:

{
  text: 'Hello QuickApp',        //标题栏文字
  textColor: '#ffff',            //文字颜色
  backgroundColor: '#434343',    //背景颜色
  backgroundOpacity: '0.8',      //背景透明度
  menu: false,      //是否在标题栏右上角显示菜单按钮 | 设置当前
}
属性类型参数描述
$elementFunctionid: String获取指定id的组件dom对象,如果没有指定id,则返回根组件dom对象用法:this.$element('xxx')获取id为xxx的组件实例对象 this.$element() 获取根组件实例对象
$rootFunction获取顶层ViewModel
$parentFunction获取父亲ViewModel
$childFunctionid: String获取指定id的自定义组件的ViewModel用法:this.$child('xxx') 获取id为xxx的div组件ViewModel
$vm deprecated Functionid: String请使用上面this.$child('xxx')替代
$rootElement deprecated Function请使用上面this.$element()替代
$forceUpdateFunction强制页面刷新
公共属性类型参数描述
$setFunctionkey: String
value: Any
添加数据属性,必须在onInit函数中使用,用法:this.$set('key',value)
$deleteFunctionkey: String删除数据属性,如果在onInit函数中使用,用法:this.$delete('key')
元素属性/方法类型参数描述
$setFunctionkey: String
value: Any
添加数据属性,用法:this.$vm('id').$set('key',value)
$deleteFunctionkey: String删除数据属性,用法:this.$vm('id').$delete('key')
$onFunctioneventName: String<br/>handler: Function在当前页面注册监听事件, 可监听$emit()$dispatch()$broadcast()等触发的自定义事件,不能用于注册组件节点的事件响应
$offFunctioneventName: String<br/>handler: Function移除事件监听,参数 fnHandler 为可选,传递仅移除指定的响应函数,不传递则移除此事件的所有监听
$emitFunctioneventName: String <br/>data: Object触发当前实例监听事件函数,与 $on() 配合使用

* 注意,获取元素应该在页面已渲染后,如 onReady 事件中或 onReady 事件执行完以后。

页面设计

  • 布局和尺寸
  1. 采用 border-box 模型且不支持 box-sizing 属性
  2. 设计稿1px / 设计稿基准宽度 = 框架样式1px / 项目配置基准宽度(项目配置基准宽度:/src/manifest.jsonconfig.designWidth 的值,默认750)
  • CSS
  1. 可以使用内联样式、tag选择器、class选择器、id选择器来为组件设置样式
  2. 仅可以使用并列选择、后代选择器、子代选择器
  3. 支持@import引入外部样式、内联样式、行内样式
  4. 颜色值不支持缩写,伪类支持不完全(支持:disabled,:checked,:focus等)

通用

  1. 通用事件:click, longpress, focus, blur, appear(组件出现),disappear(组件消失),swipe(快速滑动,参数direction:[left|right|up|down])
  2. 通用属性: id, class, style, if, elif, else, for, show, disabled 等;
  3. 通用样式: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 一样

    1. 支持样式 flex-direction, flex-wrap, justify-content, align-items, align-content
  • <popup>: 气泡框

    1. 支持属性 target 和 placement
    2. 支持样式 mask-color
    3. 支持事件 visibilitychange
    4. 自组件只能是<text>
  • <refresh>: 下拉刷新

    1. 支持属性 offset 和 refreshing
    2. 支持样式 background-color 和 progress-color
    3. 支持事件 refresh
  • <richtext>: 富文本编辑器

    1. 支持属性 type(值为 html)
    2. 支持div样式, height 无效
    3. 不支持子组件
  • <stack>: 子组件排列方式为层叠排列,每个直接子组件按照先后顺序依次堆叠,覆盖前一个子组件

    1. 支持div样式
  • <swiper>: 轮播视图容器

    1. 支持属性 index, interval, autoplay 和 indicator(是否显示indicator)
    2. 支持样式 indicator-color, indicator-selected-color 和 indicator-size
    3. 支持事件 change
    4. 支持方法 swipeTo(index)
  • <tabs>: 选项卡

    1. 支持属性 index
    2. 支持事件 change
    3. 子组件仅支持最多一个<tab-bar>和最多一个<tab-content>
  • <tab-bar>: 用来展示tab的标签区,子组件排列方式为横向排列

    1. 支持属性 mode(scrollable|fix)
    2. 支持样式 height
    3. 支持事件 visibilitychange
  • <tab-content>: 用来展示tab的内容区,高度默认充满tabs剩余空间,子组件排列方式为横向排列

    1. 支持属性 target 和 placement
    2. 支持样式 mask-color
    3. 支持事件 visibilitychange
  • <list>: 开发者在页面中实现长列表或者屏幕滚动等效果时,习惯使用div组件做循环遍历

    1. 子组件必须是 <list-item>;
    2. 支持属性 scrollpage,默认关闭,标志是否将顶部页面中非<list>的元素随<list>一起滚动。开启 scrollpage 会降低<list>渲染性能
    3. 组件的性能优化分为: 精简 DOM 层级、复用<list-item>、细粒度划分<list-item>、关闭 scrollpage 四个方面
    4. 支持 flex-direction 和 column
    5. 具有方法scrollTo(num)和事件scroll, scrollBottom, scrollTop
  • <list-item> list 的子元素

    1. 的子组件可以是任何标签或除<list>以外的组件
    2. 有一个属性 type,type 值相同的 <list-item> 后代 DOM 必须一模一样,如果不一样,请使用不同的 type 值。type 不能为空!
    3. 支持<div>样式和 column-span,不支持 position
  • <a>: 链接

    1. 支持属性 href
    2. href 属性值可根据路由配置
    3. href还支持http和https开头的网址,点击后会打开webview加载网页
    4. href还可以通过“?param1=value1”的方式添加参数,参数可以在页面中通过this.param1的方式使用
    5. 子组件仅支持<span>
    6. 仅支持 `text
    7. 支持 sms, tel, mailto
    8. 支持样式 lines, color, font-style, font-weight(normal|bold),text-decoration, text-align, line-height, text-overflow
  • <image>: 图片

    1. 支持属性 src 和 alt
    2. 支持样式 resize-mode(cover|contain|stretch|center)
    3. 不支持子组件
  • <process>: 进度条

    1. 支持属性 percent 和 type(horizontal|circular)
    2. 支持样式 color 和 stroke-width
    3. 支持事件 visibilitychange
    4. 不支持子组件
  • <rating>: 星级评分

    1. 支持属性 numstars(总数), stepsize(步长), indicator(是否可操作)和 rating(值)
    2. 支持样式 star-background, star-secondary, star-foreground(三种状态的图片)
    3. 支持事件 change,不支持click、longpress事件
    4. 不支持子组件
  • <span>: 格式化的文本

    1. 只能作为<text><a>的子组件
    2. 不支持 show 和 disabled 属性
    3. 支持样式 color, font-size, font-style, font-weight(normal|bold),text-decoration
    4. 不支持任何事件
    5. 不支持子组件
  • <text>: 文本内容写在标签内容区,支持转义字符""

    1. 仅支持<a><span>子组件
    2. 支持样式 lines, color, font-style, font-weight(normal|bold),text-decoration, text-align, line-height, text-overflow
  • <input>: 接收用户的输入

    1. 不支持子组件
    2. 支持属性 type(button|checkbox|radio|text|email|date|time|number|password), name, value, checked 和 placeholder
    3. 支持样式 color, placeholder-color, width, height 和 font-size
    4. 支持事件 change
    5. 支持方法 focus()
  • <label>: 为input、textarea组件定义标注

    1. 不支持子组件
    2. 支持属性 target
    3. 支持样式 lines, color, font-style, font-weight(normal|bold),text-decoration, text-align, line-height, text-overflow
    4. 不支持事件
  • <option>: <select>的子组件,用来展示下拉选择具体项目

    1. 不支持子组件
    2. 支持属性 value 和 selected
    3. 不支持事件
  • <picker>: 滚动选择器,目前支持三种选择器,普通选择器,日期选择器,时间选择器。默认为普通选择器。

    1. 支持子组件
    2. 支持属性 type(text|date|time), range, start, end, value 和 selected
    3. 不支持 click 事件, 支持 change 事件
    4. 支持方法 show()
  • <select>: 下拉菜单

    1. 仅支持<option>子组件
    2. 不支持 click 事件, 支持 change 事件
  • <slider>: 滑动选择器

    1. 不支持子组件
    2. 支持属性 min, max, value 和 step
    3. 支持样式 color, selected-color, padding 仅支持 left 和 right
    4. 支持事件 change
  • <switch>: 开关选择

    1. 不支持子组件
    2. 支持属性 checked
    3. 支持事件 change
  • <textarea>: 接收用户的输入

    1. 不支持子组件
    2. 支持属性 placeholder
    3. 支持样式 color, placeholder-color 和 font-size
    4. 支持事件 change
    5. 支持方法 focus()
  • <video>: 视频播放器

    1. 支持属性 src, poster 和 autoplay
    2. 支持事件 prepared, start, pause, finish, error, seeking, seeked, timeupdate 和 fullscreenchange
    3. 支持方法 start(), pause(), setCurrentTime(seconds), requestFullscreen() 和 exitFullscreen()
  • <web>: 用于显示在线的html页面

    1. 必须声明"打开网页"接口,否则会提示缺乏权限。
    2. 支持属性 src, src 值为 Deeplink, 参考下文 Deeplink 部分
    3. 支持样式 mask-color
    4. 支持事件 titlereceive, pagestart, pagefinish 和 error
    5. 支持方法 reload(), forward(), back(), canForward(callback), canBack(callback)

接口

以下接口通过 import app from '@system.app'require('@system.app')方式引入
接口申明在 manifest 文件的 features 中,除了 @system.app使用前以外都需要申明。
  • @system.app

    1. getInfo(), 得到应用名称、版本名称、版本号、log级别,三级来源
  • @system.share

    1. 内置分享,接口声明:{"name": "system.share"}

      1. share({type: MIME Type, data:String/URL/FileList, success, fail, cancel, complete}): 分享调用
    2. 第三方分享,接口声明:{"name": "service.share","params": {"appSign": "abcdefg...","qqKey":"1234567","wxKey":"wx1234","sinaKey":"1234"}}

      1. manifest 参数说明: appSign 签名; qqKey QQ后台ID; wxKey: 微信后台ID, sinaKey 新浪后台ID
      2. getProvider(): 获取厂商信息
      3. share({shareType:int, title, summary, targetUrl,imagePath, mediaUrl, success, fail, cancel, complete})

        • 其中 shareType 默认图文0,纯文字1,纯图片2,音乐3,视频4

cancel

  • @system.router

    1. 接口声明:{"name": "system.router"}
    2. push({url, params:Object}): 跳转url
    3. replace({url, params:Object}): 跳转url, 后退不会来
    4. back(): 后退
    5. clear(): 清空历史栈
    6. getLength(): 获取历史栈长度
    7. getState(): 获取当然页面位置,名称,路径
  • @system.prompt

    1. 接口声明:{"name": "system.prompt"}
    2. showToast({message, duratuon:(0 or 1)}): 显示吐司
    3. showDialog({title:, message:, buttons:[{text,color}], success({index}), fail, cancel, complete}): 显示对话框
    4. showContextMenu({itemList:String[], itemColor:HexColor, success, fail, cancel, complete}): 显示上下文菜单
  • @system.notification

    1. 接口声明:{"name": "system.notification"}
    2. show({contentTitle, contentText, clickAction:{url}}): 显示通知
  • @system.vibrator

    1. 接口声明:{"name": "system.vibrator"}
    2. vibrate(): 震动1s
  • @system.webview

    1. 接口声明:{"name": "system.webview"}
    2. loadUrl({url}): 通过 webview 加载 url
    3. 在webview打开的网页中可以使用的api: system.go(path): url 跳转
  • @system.request

    1. 接口声明:{"name": "system.request"}
    2. upload({url, header:Object, method(POST|GET), files:{filename,name,url,type}[], data:{name,value}[], success({code,data,headers}), fail, complete}): 上传
    3. download({url, header:Object, success({token}), fail, complete}): 下载
    4. onDownloadComplete({token, success({url}), fail({code}), complete}): 监听下载任务
  • @system.fetch

    1. 接口声明:{"name": "system.fetch"}
    2. fetch({url, header:Object, method(POST|GET), files:{filename,name,url,type}[], data:{name,value}[], success({code,data,headers}), fail, complete}): 发起请求
  • @system.storage

    1. 接口声明:{"name": "system.storage"}
    2. get({key, default, success({data}), fail, complete}): 获取值
    3. set({key, value, success, fail, complete}): 存储值
    4. clear({success, fail, complete}): 清空数据
    5. delete({key, success, fail, complete}): 删除数据
  • @system.file

    1. 接口声明:{"name": "system.file"}
    2. move({srcUri, dstUri, success, fail({code}), complete}): 移动文件
    3. copy({srcUri, dstUri, success, fail({code}), complete}): 复制文件
    4. list({uri, success(fileList:{uil,list,lastModifiedTime}[]), fail({code}), complete}): 获取目录下文件列表
    5. get({uri, success({uil,list,lastModifiedTime}), fail({code}), complete}): 获取文件信息
    6. delete({uri, success, fail(code**), complete}): 获取文件信息
  • @system.barcode (需要用户授权)

    1. 接口声明:{"name": "system.barcode"}
    2. scan({success({result}), fail(code:201用户拒绝), cancel, complete}): 扫描二维码
  • @system.sensor

    1. 接口声明:{"name": "system.sensor"}
    2. subscribeAccelerometer({callback(x,y,c)}): 获取重力感应数据
    3. unsubscribeAccelerometer(): 停止获取重力感应数据
    4. subscribeCompass({callback(direction)}): 获取罗盘数据
    5. unsubscribeCompass(): 停止获取罗盘数据
    6. subscribeProximity({callback(distance)}): 获取距离感应数据
    7. unsubscribeProximity(): 停止获取距离感应数据
    8. subscribeLight({callback(intensity)}): 获取光线感应数据
    9. unsubscribeLight(): 停止获取光线感应数据
  • @system.clipboard

    1. 接口声明:{"name": "system.clipboard"}
    2. set({text, success, fail, complete}): 写入
    3. get({success({text}), fail, complete}): 读取
  • @system.geolocation (需要用户授权)

    1. 接口声明:{"name": "system.geolocation"}
    2. getLocation({timeout, success({longitude, latitude}), fail, complete}): 获取地理位置
    3. subscribe({callback(longitude, latitude), fail}): 监听用户位置
    4. unsubscribe(): 取消监听用户位置
  • @system.shortcut (需要用户授权)

    1. 接口声明:{"name": "system.shortcut"}
    2. hasInstalled({success, fail, complete}): 是否已创建桌面图标
    3. install({success, fail, complete}): 创建桌面图标
  • @system.calandar (需要用户授权)

    1. 接口声明:{"name": "system.calandar"}
    2. insert({title, description, startDate:number, endDate:number, timezone:string, allDay:boolean是否整天, rrule:string重复规则, remindMinutes:number[]提前提醒时间, organizer: string, success, fail, cancel}): 插入日历事件
  • @system.network

    1. 接口声明:{"name": "system.network"}
    2. getType({success(metered是否按流量计费, type网络类型), fail, complete}): 获取网络类型
    3. subscribe({callback(metered, type), fail}): 监听网络情况
    4. unsubscribe(): 取消监听网络情况
  • @system.device (需要用户授权)

    1. 接口声明:{"name": "system.device"}
    2. getInfo({success({brand, manufacturer, model, product, osType, osVersionName, osVersionCode, platformVersionName, platformVersionCode, language, region, screenWidth, screenHeight}), fail, complete}): 获取设备基本信息
    3. getId({type(device|mac|user|advertising)[], success({device, mac, user, advertising}), fail, complete}): 获取设备标识
    4. getDeviceId({success({deviceId}), fail, complete}): 获取设备ID
    5. getUserId({success({userId}), fail, complete}): 获取用户ID
    6. getAdvertisingId({success({advertisingId}), fail, complete}): 获取广告ID
    7. getTotalStorage({success({totalStorage}), fail, complete}): 获取总容量
    8. getAvailableStorage({success({availableStorage}), fail, complete}): 获取可用容量
    9. getCpuInfo({success({cpuInfo}), fail, complete}): 获取cpu信息
  • @system.brightness

    1. 接口声明:{"name": "system.brightness"}
    2. getValue({success({value}), fail, complete}): 获取屏幕亮度
    3. setValue({value, success(value:0手动;1自动), fail, complete}): 设置屏幕亮度
    4. getMode({success(value:0手动;1自动), fail, complete}): 获取屏幕亮度模式
    5. setMode({value, success, fail, complete}): 设置屏幕亮度模式 1. 接口声明:{"name": "system.volume"}
  • @system.volume

    1. 接口声明:{"name": "system.volume"}
    2. getMediaValue({success(value:0到1), fail, complete}): 获取音量
    3. setMediaValue({value, success, fail, complete}): 设置音量
  • @system.battary

    1. 接口声明:{"name": "system.battary"}
    2. getStatus({success(charging, level:0到1), fail, complete}): 获取当前电池状态
  • @system.package

    1. 接口声明:{"name": "system.package"}
    2. hasInstalled({package包名, success(result:boolean), fail, complete}): 判断是否安装了某个应用
    3. install({package, success(result:boolean), fail, complete}): 安装应用
    4. 利用路由中的 push 操作打开应用
  • @system.record (需要用户授权)

    1. 接口声明:{"name": "system.record"}
    2. start({success({url}), fail, complete}): 开始录音
    3. record.stop(): 停止录音
  • @system.cipher

    1. 接口声明:{"name": "system.cipher"}
    2. rsa({action:encrypt|decrypt, text, key加密为公钥|解密为私钥, transformation补充项,success({text}), fail, complete}): rsa 加密解密
  • @system.media (需要用户授权)

    1. 接口声明:{"name": "system.media"}
    2. takePhoto({success({uri}), fail, complete, cancel}): 拍照
    3. takeVideo({success({uri}), fail, complete, cancel}): 录像
    4. pickImage({success({uri}), fail, complete, cancel}): 选择图片
    5. pickVideo({success({uri}), fail, complete, cancel}): 选择视频
  • @system.image

    1. 接口声明:{"name": "system.image"}
    2. getImageInfo({uri, success({uri, width, height, size}), fail, complete, cancel}): 获取图片基础信息
    3. compressImage({uri, quality:1到100, ratio:number缩放比, format:图片格式, success({uri, width, height, size}), fail, complete, cancel}): 压缩图片
    4. applyOperations({uri, operations:Object[](如下), quality, format, success({uri}), fail, complete, cancel}}): 对图片按顺序执行编辑操作

      • 剪裁: {action: 'crop', x, y, width, height}
      • 缩放: {action: 'scale', scaleX, scaleY}
      • 旋转: {action: 'rotate', degree}
    5. editImage({uri, success({uri}), fail, complete, cancel}): 使用编辑器编辑图片
  • @system.audio

    1. 接口声明:{"name": "system.audio"}
    2. play(): 播放
    3. pause(): 暂停
    4. 属性: src, currentTime, duration, autoplay, loop, volume, muted
    5. 事件: play, pause, loadeddata, ended, durationchange, error, timeupdate
  • @system.push

    1. 接口声明:{"name": "system.push"}
    2. getProvider(): 获取服务提供商
    3. subscribe({success({regId}), fail, complete}): 订阅push
    4. unsubscribe(): 取消订阅push
    5. on({callback(messageId, data)}): 添加push事件回调
    6. off(): 移除push事件回调
  • @system.pay

    1. 接口声明:{"name": "system.pay"}
    2. getProvider(): 获取服务提供商
    3. pay({orderInfo:String, success({code, message, result}), fail({code, message}), complete}): 付款
  • @system.stats

    1. 接口声明:{"name": "system.stats"}
    2. getProvider(): 获取服务提供商
    3. recordCountEvent({category, key, map}): 计数类型事件
    4. recordCalculateEvent({category, key, value, map}): 计算类型事件
  • @system.account

    1. 接口声明:{"name": "system.account"}
    2. getProvider(): 获取服务提供商
    3. authorize({type:string(code|token), redirectUri, scope, state, success({state, code, accessToken, tokenType, expiresIn, scope}), fail, complete): 认证
    4. getProfile({token, success({openid, id, unionid, nickname, avatar}), fail, complete}): 获取用户认证信息
  • @system.alipay

    1. 接口声明:{"name": "system.alipay"}
    2. pay({orderInfo:string, callback}): 支付
    3. 支付宝支付细节,请查看请求参数说明文档
  • @system.wxpay

    1. 接口声明:{"name": "service.wxpay", "params": {"package": "com.your.package", "sign": "abcdefg", "url": "http://your.domain/page"}}
    2. 两种方式的 manifest 配置:

      • app 原生:package: 包名,sign: 签名
      • web 方式:url:H5 url
    3. getType(): 返回调用方式(none|APP|MWEB)
    4. pay({prepayid, extra, success({prepayid,final_url}), fail(code**), complete}): 支付

      • extra app 版参数如下

        1. app_id: 微信支付订单中的app_id
        2. partner_id: 微信支付订单中的partner_id
        3. package_value: 微信支付订单中的package_value
        4. nonce_str: 微信支付订单中的nonce_str
        5. time_stamp: 微信支付订单中的time_stamp
        6. order_sign: 微信支付订单中的order_sign
      • extra app 版参数如下

        1. mweb_url: 在微信的支付服务器下单以后,微信返回的 MWEB_URL,在CP用于微信支付的h5页面中,直接将mweb_url取出后跳转过去即可,但这个做法并不是强制的,您也可以通过其他自定义键值向您自己的服务器换取MWEB_URL
        2. custome_key: 其他的自定义键值,cp可以根据需要增加其他自己认为需要的键名和键值
    5. 微信支付细节,请参考微信网页支付微信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.$app.$data 实现,相当于绑定数据到全局了,这个不再举例

页面间通信

这个部分和 HTML5 中的同源页面通信如出一辙。会利用到一个构造函数 new BroadcastChannel(string), 它接受一个字符串参数,作为实例的频道名称。它的实例具有以下属性和方法:

名称类型参数描述
nameString-频道名称,区分不同的消息频道(注意:不同频道之间不可通信)。
postMessageFunctionAny: 消息内容用于在当前频道中广播消息。
onmessageFunctionEvent:消息对象订阅消息。在频道中接收到广播消息之后,会给所有订阅者派发消息事件。
closeFunction-关闭当前的频道。

其中 onmessage 事件有2个属性(通过 event 对象访问):

属性类型描述
typeString"message"
dataAny接收到的消息内容

由于和 HTML5 用法一样,这里就不演示了。

组件通信

父子组件通信

父子组件使用见 template 部分

  • 父组件到子组件

    1. 子组件通过 props 获取父组件传入的值,见上文 template 部分
    2. 通过 this.watch(props, callback) 监控传入数据变化并调用回调函数
    3. 父组件通过this.$broadcast()完成事件触发,子组件通过$on()绑定事件并响应
  • 子组件到父组件

    1. 父子组件传对象类型属于引用传递,可以直接修改父组件传入对象改变父组件数据
    2. 子组件通过this.$dispatch()完成事件触发,父组件通过$on()绑定事件并响应
    3. 子组件通过this.$emit()触发在节点上绑定的事件来执行父组件的方法

* 注:this.$broadcast()this.$emit()this.$dispatch() 参数一致
* 注:触发时传递参数,再接收时使用event.detail来获取参数
* 注:当传递结束后,可以调用event.stop()来结束传递

Deeplink

配合<web>标签框架支持通过链接从外部打开应用,格式

  1. http://hapjs.org/app/<package>/[path][?key=value]
  2. https://hapjs.org/app/<package>/[path][?key=value]
  3. 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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值