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

属性 类型 默认值 必填 描述
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页面的生命周期接口的调用顺序:

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

应用生命周期

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

预置对象

全局对象 (通过 this 访问)

的属性 类型 参数 描述
$app Object - 应用对象
$app.$def Object - 获取在app.ux中暴露的对象
$app.$data 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
value: Any
添加数据属性,必须在onInit函数中使用,用法:this.$set('key',value)
$delete Function key: String 删除数据属性,如果在onInit函数中使用,用法:this.$delete('key')
元素属性/方法 类型 参数 描述
$set Function key: String
value: Any
添加数据属性,用法:this.$vm('id').$set('key',value)
$delete Function key: String 删除数据属性,用法:this.$vm('id').$delete('key')
$on Function eventName: String<br/>handler: Function 在当前页面注册监听事件, 可监听$emit()$dispatch()$broadcast()等触发的自定义事件,不能用于注册组件节点的事件响应
$off Function eventName: String<br/>handler: Function 移除事件监听,参数 fnHandler 为可选,传递仅移除指定的响应函数,不传递则移除此事件的所有监听
$emit Function eventName: 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), 它接受一个字符串参数,作为实例的频道名称。它的实例具有以下属性和方法:

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

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

属性 类型 描述
type String "message"
data Any 接收到的消息内容

由于和 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>

Faremax
1.7k 声望705 粉丝