快应用简介

快应用是一种新的应用形态,以往的手机端应用主要有两种方式:网页、原生应用;网页无需安装,却体验不是很好;原生应用体验流畅,却需要从应用商店下载安装,难以一步直达用户;快应用的出现,就是希望能够让用户无需下载安装,并且还能流畅的体验应用内容。

为了达到上面的目标,快应用建立一种新的语言开发规范,同时提供一系列的开发套件辅助支持。简单来说,开发者主要利用前端知识与技能,以及对应的IDE,手机设备就可以做原型的开发。快应用使用前端技术栈开发,原生渲染,同时具备H5与原生应用的双重优点,开发者使用的前端技术栈资料多,学习成本底。

2018年3月份,由小米,OPPO,VIVO,华为等10家国内主流厂商成立了快应用联盟,从技术规范层面做了统一,并保证了开发者开发的快应用可以直接在所有的联盟内厂商的手机设备上运行。

快应用框架深度集成进各手机厂商的手机操作系统中,可以在操作系统层面形成用户需求与应用服务的无缝连接,很多只用在原生应用中才能使用的功能,在快应用中可以很方便的实现,享受原生应用体验,同时不用担心分发留存等问题,资源消耗也比较少。

对于每台手机设备,应用可以从多个系统入口,引用用户体验产品。比如:全局搜索、负一屏、浏览器搜索等。

 

前言

与微信小程序的比较

  • 二者都采用前端技术栈,快应用是native 渲染,性能体验会比较好,而小程序目前是webview渲染
  • 二者开发框架和规范不同,所以代码写法上有差异,快应用的css支持能力较弱
  • 快应用基于native,可以调起丰富的系统api,小程序在此方面会有些无力

快应用入口

  • 应用商店
  • 桌面图标
  • 全局搜索
  • 浏览器搜索
  • 网页跳转
  • 负一屏
  • 智能推送
  • 智慧识屏
  • 场景化入口(短信按钮、应用卸载替换、二维码、传送门)

快应用优点

  • 轻松调起更多系统api
  • 各厂商的流量扶持
  • native渲染,deeplink入口,原生桌面入口,push能力

一、环境搭建

1.1 安装NodeJS

需安装6.0以上版本的NodeJS

1.2 安装hap-toolkit

// hap -V // 会显示安装版本信息
npm install -g hap-toolkit

1.3 创建项目工程

hap init projectName

// 增加编译支持
hap update --force

cd projectName && npm i

生成的目录结构

├── sign rpk //包签名模块
│ └── debug //调试环境
│ ├── certificate.pem //证书文件
│ └── private.pem //私钥文件
├── src
│ ├── Common //公用的资源和组件文件
│ │ └── logo.png //应用图标
│ ├── Demo //页面目录
│ | └── index.ux //页面文件,可自定义页面名称
│ ├── app.ux //APP文件,可引入公共脚本,暴露公共数据和方法等
│ └── manifest.json //项目配置文件,配置应用图标、页面路由等
└── package.json //定义项目需要的各种模块及配置信息
  • src:项目源文件夹
  • sign:签名模块,当前仅有debug签名,如果内测上线,请添加release文件夹,增加线上签名;签名生成方法详见文档编译工具

编译项目

  • npm run release # 发布程序包,在 /dist/.signed.rpk,注意需要使用 release 签名模块
  • npm run build # 生成 builddist 两个目录。前者是临时产出,后者是最终产出
  • npm run watch # 文件保存时自动编译和调试

手动编译项目

在项目的根目录下,运行如下命令进行编译打包,生成rpk包

npm run build
  • 编译打包成功后,项目根目录下会生成文件夹:builddist
  • build:临时产出,包含编译后的页面js,图片等
  • dist:最终产出,包含rpk文件。其实是将build目录下的资源打包压缩为一个文件,后缀名为rpk,这个rpk文件就是项目编译后的最终产出

自动编译项目

  • 每次修改源代码文件后,都自动编译项目
npm run watch

在安卓手机上安装调试工具

https://www.quickapp.cn/docCenter/post/69

快应用简介_第1张图片

image.png

1.4 连接手机进行调试

注意:一定要注意手机连接的wifi与电脑所连接的网络需要在同一局域网和网段,需要能够相互访问。

  • 在项目根目录下执行如下命令,启动HTTP调试服务器:(server前需要先npm run build
npm run server
  • 开发者可以通过命令行终端或者调试服务器主页看到提供扫描的二维码
  • 开发者通过快应用调试器扫码安装按钮,扫码安装待调试的rpk文件
  • 开发者点击快应用调试器中的开始调试按钮,开始调试

打开之前安装的快应用调试助手扫描即可预览

快应用简介_第2张图片

image.png

扫描二维码之后点击开始调试,会调出devtool工具本地调试

快应用简介_第3张图片

image.png

快应用简介_第4张图片

image.png

1.5 安装Hap Extension

启动Visual Studio Code,打开项目,点击左上侧扩展,搜索hap,点击安装Hap Extension

  • 更多详情 https://doc.quickapp.cn/tutorial/getting-started/code-edit-conf.html

二、快应用结构分析

2.1 文件组织

一个应用包含:描述项目配置信息的manifest文件,放置项目公共资源脚本的app.ux文件,多个描述页面/自定义组件的ux文件

├── sign                            rpk包签名模块
    └── debug                       调试环境
            └── certificate.pem     证书文件
            └── private.pem         私钥文件
├── src
   ├── Common                       公用的资源和组件文件
            └──logo.png             应用图标
   ├── Demo                         页面目录
            └── index.ux            页面文件,可自定义页面名称
   ├── app.ux               APP文件,可引入公共脚本,暴露公共数据和方法等
   └── manifest.json                项目配置文件,配置应用图标、页面路由等
└── package.json                    定义项目需要的各种模块及配置信息

目录的简要说明如下

  • src:项目源文件夹
  • sign:签名模块(当前仅有debug签名,如果内测上线,请添加release文件夹,增加线上签名)

2.2 源码文件

APP,页面和自定义组件均通过ux文件编写,ux文件由template模板、style样式和script脚本3个部分组成,一个典型的页面ux文件示例如下






2.3 manifest配置

https://doc.quickapp.cn/framework/manifest.html

{
    # 包名,区分不同应用的唯一id,因为名称其实是可以一样的
    "package": "com.application.demo",

    # 应用名称
    "name": "hi",

    # 版本管理的话,每次更新将versionCode自增1即可
    "versionName": "1.0.0",
    "versionCode": "1",
    "minPlatformVersion": "101",

    # 程序的入口icon,所有关于文件的引用统一使用根目录
    # 根目录对应src文件夹
    "icon": "/Common/logo.png",

    # 
    "features": [
        { "name": "system.prompt" },
        { "name": "system.router" },
        { "name": "system.shortcut" }
    ],

    "permissions": [
        { "origin": "*" }
    ],

    # 配置相关
    "config": {
        # 这里的设置是log输出的最低等级
        # 如果是warn的话,info类型将不会输出
        # 等级请参考js中的console日志
        "logLevel": "off"
    },

    # 路由
    # 这里会配置应用入口的页面
    # 所有的页面都需要在这里配置
    # 会把页面与对应的页面文件对应起来
    # 经过配置之后可以通过/Demo访问到Demo目录下的index.ux页面
    "router": {
        "entry": "Demo",
        "pages": {
            "Demo": {
                # 这里对应的Demo文件夹里的index.ux
                "component": "index"
            },
            "DemoDetail": {
                "component": "index"
            },
            "About": {
                "component": "index"
            }
        }
    },
    
    # 配置页面UI显示
    # 主要分为两种,页面公有与页面私有
    "display": {
        # 这三个都是所有页面公有的,顶部titleBar内容
        "titleBarText": "public title"
        "titleBarBackgroundColor": "#f2f2f2",
        "titleBarTextColor": "#414141",

        # 会增加一个导航栏
        "menu": true,

        # 页面私有内容
        "pages": {
            "Demo": {
                # 这里面的内容就是每个页面私有的了
                "titleBarText": "示例页",
                "menu": false
            },
            "DemoDetail": {
                "titleBarText": "详情页"
            },
            "About": {
                "menu": false
            }
        }
    }
}
  • package 应用包名,确认与原生应用的包名不一致,推荐采用com.company.module的格式,如:com.example.demo
  • name 应用名称,6个汉字以内,与应用商店保存的名称一致,用于在桌面图标、弹窗等处显示应用名称
  • icon 应用图标,提供192x192大小的即可
  • versionName 应用版本名称,如:"1.0"
  • versionCode 应用版本号,从1自增,推荐每次重新上传包时versionCode+1
  • minPlatformVersion 支持的最小平台版本号,兼容性检查,避免上线后在低版本平台运行并导致不兼容;如果不填按照内测版本处理
  • features 接口列表,绝大部分接口都需要在这里声明,否则不能调用,详见每个接口的文档说明
  • config 系统配置
    • logLevel:打印日志等级,分为off,error,warn,info,log,debug
    • designWidth:页面设计基准宽度,根据实际设备宽度来缩放元素大小
  • router 路由信息
    • entry:首页名称
    • pages:页面配置列表,key值为页面名称(对应页面目录名,例如Hello对应'Hello'目录),value为页面详细配置page,详见下面说明
    • router.page 用于定义单个页面路由信息
      • component: 页面对应的组件名,与ux文件名保持一致,例如'hello' 对应 'hello.ux'
      • path 页面路径,例如“/user”,不填则默认为/<页面名称>。path必须唯一,不能和其他pagepath相同。下面pagepath因为缺失,会被设置为“/Index”"Index": {"component": "index"}
      • filter: 声明页面可以处理某种请求
  • display UI显示相关配置
    • backgroundColor 窗口背景颜色
    • fullScreen 是否是全屏模式,默认不会同时作用于titleBartitleBar需要继续通过titleBar控制
    • titleBar 是否显示titleBar
    • titleBarBackgroundColor标题栏背景色
    • titleBarTextColor 标题栏文字颜色
    • titleBarText 标题栏文字(也可通过页面跳转传递参数(titleBarText)设置)
    • menu 是否显示标题栏右上角菜单按钮
    • pages 各个页面的显示样式,key为页面名(与路由中的页面名保持一致),value为窗口显示

2.4 app.ux

当前app.ux编译后会包含manifest配置信息(可以在npm run build之后查看文件内容),所以请不要删除/**manifest**/的注释内容标识

  • 您可以在

    2.6 template模板

    
      
      
    
    
    
       
    
    
    
    
    
    
    
    

    2.7 script脚本

    2.7.1 模块声明

    可以通过import引入功能模块,在代码中调用模块方法

    import fetch from "@system.fetch"
    

    也可以一次引入所有的模块,例如

    import system from "@system"
    
    • 在代码中使用system.network来调用接口方法

    2.7.2 对象

    2.7.2.1 页面级组件

    data(废弃)

    • 页面级组件的数据模型,能够转换为JSON对象
    • 如果是函数,返回结果必须是对象,在组件初始化时会执行函数获取结果作为data的值
    • 使用data方式声明的属性会被外部数据覆盖,因此存在一定安全风险,推荐使用下面的public,protected,rivate来声明属性(注意:它们不能与data同时声明)

    public

    页面级组件的数据模型,影响传入数据的覆盖机制:public内定义的属性允许被传入的数据覆盖,如果外部传入数据的某个属性未被声明,在public中不会新增这个属性

    protected

    页面级组件的数据模型,影响传入数据的覆盖机制:protected内定义的属性,允许被应用内部页面请求传递的数据覆盖,不允许被应用外部请求传递的数据覆盖

    private

    页面级组件的数据模型,影响传入数据的覆盖机制:private内定义的属性不允许被覆盖

     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(){
              // 外部事件定义
           }
        }
      }
    

    2.7.2.2 自定义组件

    data

    自定义组件的数据模型,能够转换为JSON对象;属性名不能以$或_开头, 不要使用for, if, show, tid等保留字
    如果是函数,返回结果必须是对象,在组件初始化时会执行函数获取结果作为data的值

    props

    • 定义组件外部可传入的所有属性
    • 在模板代码中,请使用短横线分隔命名代替驼峰命名。如,属性定义props: ['propA'],可通过方式传递到组件内部

    prop验证

    在自定义组件中,可将props定义为带验证需求的对象。其中,key为属性名,value为属性对应的验证需求。验证失败则输出错误提示日志,增加prop验证有利于规范自定义组件的使用

    属性 类型 描述
    type - 检查属性值的类型。支持单一类型和多种可能类型,可在原生和自定义构造函数中任意选择,单独或组合使用。原生构造函数:String Number Boolean Function Object Array Symbol
    default - 设置属性的默认值
    required Boolean 设置属性是否必填
    validator Function 设置自定义验证函数。若函数的返回值为真,则通过验证;否则验证失败
    export default {
        props: {
          // 单一类型检查的简写
          propA: Number,
          // 多种可能类型的简写
          propB: [String, Number],
          // 必填的字符串
          propC: {
            type: String,
            required: true
          },
          // 带默认值的数字
          propD: {
            type: Number,
            default: 100
          },
          // 带有默认值的对象
          propE: {
            type: Object,
            default () {
              return { message: 'hello' }
            }
          },
          // 自定义验证函数
          propF: {
            validator (value) {
              return value === 'hello'
            }
          }
        }
      }
    

    2.7.2.3 公共对象

    属性 类型 描述
    $app Object 应用对象
    $page Object 页面对象
    $valid Boolean 页面对象是否有效
    $visible Boolean 页面是否处于用户可见状态

    2.7.2.4 应用对象

    可通过$app访问

    属性 类型 描述
    $def Object 使用this.$app.$def获取在app.ux中暴露的对象
    $data Object 使用this.$app.$data获取在manifest.jsonconfig.data中声明的全局数据

    2.7.2.5 页面对象

    可通过$page访问

    属性 类型 描述
    action String 获取打开当前页面的action。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined
    uri String 获取打开当前页面的uri。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined

    2.7.3 方法

    2.7.3.1 数据方法

    属性 类型 参数 描述
    $set Function key: String value: Any 添加数据属性,用法:this.$set('key',value) this.$vm('id').$set('key',value)
    $delete Function key: String 删除数据属性,用法:this.$delete('key') this.$vm('id').$delete('key')

    2.7.3.2 公共方法

    属性 描述
    $element 获取指定id的组件dom对象,如果没有指定id,则返回根组件dom对象用法: this.$element('xxx') 获取idxxxdiv组件实例对象 this.$element() 获取根组件实例对象
    $root 获取顶层ViewModel
    $parent 获取父亲ViewModel
    $child 获取指定id的自定义组件的ViewModel用法:this.$child('xxx') 获取idxxxdiv组件ViewModel
    $vm deprecated 请使用上面this.$child('xxx')替代
    $rootElement deprecated 请使用上面this.$element()替代
    $forceUpdate 更新ViewModel数据,可能会触发DOM操作,如:创建节点、更新节点、删除节点等;这些DOM操作不一定在数据更新时立即执行,而是在开发者的业务代码执行后触发;若开发者期望数据更新时立即执行相应的DOM操作,可使用:this.$forceUpdate();一般不推荐使用

    2.7.3.3 事件方法

    属性 参数 描述
    $on type: String 事件名
    handler: Function事件句柄函数
    添加事件处理句柄用法:this.$on('xxxx', this.fn) fn是在

    指令if与指令show

    • if条件指令,是指if/elif/else这3个相关指令,用于控制是否增加或者删除组件;
    • show指令,是指是否显示组件,用于控制组件的显示状态,并不会从DOM结构中删除
    
    
    
    
    
    
    • if/elif指令的值为false时,节点会从页面中移除,当if/elif指令值为true,组件会动态插入节点中;
    • show指令的值为true时,节点可见, - 当其值为false时,组件不可见,但节点仍会保留在页面DOM结构中

    组件block

    block组件是表达逻辑区块的组件,没有对应的Native组件。可以使用实现更为灵活的"列表/条件渲染"。如在上使用for指令和if指令

    
    
    
    
    
    

    组件slot

    slot节点用于向开发者额外开发的自定义ux组件中插入内容

    • 通常自定义组件的模板中提供slot组件,当该组件被引入到页面组件中后,开发者可以灵活定义该自定义组件内部的子内容
    //自定义组件part1.ux
    
    
    
    
    
    
    //自定义组件使用者页面index.ux
    
    
    
    
    
    
    
    
    

    在子组件中使用slot组件,使得子组件接纳调用者传入的子内容,从而动态渲染子组件,得到最终的页面

    三、生命周期

    3.1 APP的生命周期

    当前为APP的生命周期提供了两个回调函数:onCreate, onDestroy;可在app.ux中定义回调函数

    快应用简介_第5张图片

    image.png

    import {
      natives
    } from './util/asyncNatives'
    
    export default {
      onCreate () {
        console.info('Application onCreate')
      },
      onDestroy () {
        console.info('Application onDestroy')
      },
      // 暴露给所有页面,在页面中通过:this.$app.$def.method1()访问
      method1 () {
        console.info('这是APP的方法')
      },
      // 暴露给所有页面,在页面中通过:this.$app.$def.data1访问
      data1: {
        name: '这是APP存的数据'
      },
      natives
    }
    
    • app.ux中,开发者可以做一些独立于页面的操作。比如:引入公共的JS资源,然后暴露给所有页面
    • app.ux中,通过this.$def访问app.ux中定义的数据和方法
    console.info(`获取:APP文件中的数据:${this.$def.data1.name}`)
    console.info(`执行:APP文件中的方法`, this.$def.method1())
    console.info(`获取:manifest.json的应用名称:${this.$def.manifest.name}`)
    console.info(`获取:manifest.json的config.data的数据:${this.$data.name}`)
    

    pageName.ux中,通过this.$app.$def访问app.ux中定义的数据和方法

    console.info(`获取:APP文件中的数据:${this.$app.$def.data1.name}`)
    console.info(`执行:APP文件中的方法`, this.$app.$def.method1())
    console.info(`获取:manifest.json的应用名称:${this.$app.$def.manifest.name}`)
    console.info(`获取:manifest.json的config.data的数据:${this.$app.$data.name}`)
    

    关于app.$def

    • 前者代表框架为开发者暴露提供的APP对象;后者代表开发者在app.ux中导出的对象,放置业务相关的全局数据和方法
    • 前者对象拥有onCreate, onDestroy生命周期;当应用启动时会执行onCreate方法,里面执行this.variable1的赋值是在$app对象上
    • 后者对象中的onCreate, onDestroy方法并不会执行,作用仅仅只是把方法复制到前者对象上而已
    • 这些全局方法在页面中:既可以通过this.$app.method1()调用,也可以通过this.$app.$def.method1()调用;不同之处在于前者可以取到之前赋值的variable1变量,而后者不可以取到(因为之前的赋值是在$app对象上执行的)

    3.2 页面生命周期

    快应用简介_第6张图片

    image.png

    onInit()

    表示ViewModel的数据已经准备好,可以开始使用页面中的数据

    private: {
      // 生命周期的文本列表
      lcList: []
    },
    onInit () {
      this.$page.setTitleBar({ text: '生命周期' })
    
      this.lcList.push('onInit')
    
      console.info(`触发:onInit`)
      console.info(`执行:获取ViewModel的lcList属性:${this.lcList}`)   // 执行:获取ViewModel的lcList属性:onInit
      // $app信息
      console.info(`获取:manifest.json的config.data的数据:${this.$app.$data.name}`)
      console.info(`获取:APP文件中的数据:${this.$app.$def.data1.name}`)
      console.info(`执行:APP文件中的方法`, this.$app.$def.method1())
    }
    

    onReady()

    表示ViewModel的模板已经编译完成,可以开始获取DOM节点(如:this.$element(idxxx)

    onReady () {
      this.lcList.push('onReady')
    
      console.info(`触发:onReady`)
      console.info(`执行:获取模板节点:${this.$rootElement()}`)   // 执行:获取模板节点:
    ...
    }

    onShow(), onHide()

    页面被切换隐藏时调用onHide(),页面被切换重新显示时调用onShow()

    • 判断页面的显示状态,可以调用ViewModel$visible属性:true表示显示,false表示隐藏
    onShow () {
      this.lcList.push('onShow')
    
      console.info(`触发:onShow`)
      console.info(`执行:获取页面显示状态属性:${this.$visible}`)  // true
    },
    onHide () {
      this.lcList.push('onHide')
    
      console.info(`触发:onHide`)
      console.info(`执行:获取页面显示状态属性:${this.$visible}`)  // false
    }
    

    onDestroy()

    页面被销毁时调用,被销毁的可能原因有:用户从当前页面返回到上一页,或者用户打开了太多的页面,框架自动销毁掉部分页面,避免占用资源

    • 所以,页面销毁时应该做一些释放资源的操作,如:取消接口订阅监听geolocation.unsubscribe()
    onDestroy () {
      console.info(`触发:onDestroy`)
      console.info(`执行:页面要被销毁,销毁状态:${this.$valid},应该做取消接口订阅监听的操作: geolocation.unsubscribe()`)    // true,即将销毁
      setTimeout(function () {
        console.info(`执行:页面已被销毁,不会执行`)                // 页面已销毁,不会执行
      }.bind(this), 0)
    }
    

    onBackPress()

    当用户点击返回实体按键、左上角返回菜单、调用返回API时触发该事件

    • 如果事件响应方法最后返回true表示不返回,自己处理业务逻辑(完毕后开发者自行调用API返回);否则:不返回数据,或者返回其它数据:表示遵循系统逻辑:返回到上一页
    onBackPress () {
      console.info(`触发:onBackPress`)
    
      // true:表示自己处理;否则默认返回上一页
      // return true
    }
    

    返回上一页的接口API:router.back()

    onMenuPress()

    当使用原生的顶部标题栏时,可以通过manifest.json中的menu属性配置是否显示右上角的菜单

    onMenuPress () {
      this.lcList.push('onMenuPress')
    
      console.info(`触发:onMenuPress`)
    }
    

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

    • 打开页面A:onInit() -> onReady() -> onShow()
    • 在页面A打开页面B:onHide()
    • 从页面B返回页面A:onShow()
    • A页面返回:onBackPress() -> onHide() -> onDestroy()

    四、置顶对象

    • $app 应用对象
    • $app.$def 获取在app.ux中暴露的对象
    • $app.$data 获取在manifest.jsonconfig.data中声明的全局数据
    • $page 页面对象
    • $page.action 获取打开当前页面的action。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined。参见manifest
    • $page.uri 获取打开当前页面的uri。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined
    • $page.setTitleBar 设置页面标题
    • $valid 页面对象是否有效
    • $visible 页面是否处于用户可见状态

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

    {
      text: 'Hello QuickApp',        //标题栏文字
      textColor: '#ffff',            //文字颜色
      backgroundColor: '#434343',    //背景颜色
      backgroundOpacity: '0.8',      //背景透明度
      menu: false,      //是否在标题栏右上角显示菜单按钮 | 设置当前
    }
    

    五、全局对象

    • $element 获取指定id的组件dom对象,如果没有指定id,则返回根组件dom对象用法:this.$element('xxx')获取id为xxx的组件实例对象 this.$element() 获取根组件实例对象
    • $root 获取顶层ViewModel
    • $parent 获取父亲ViewModel
    • $child 获取指定id的自定义组件的ViewModel用法:this.$child('xxx') 获取idxxxdiv组件ViewModel
    • $vm(弃用) 请使用上面this.$child('xxx')`替代
    • $forceUpdate 强制页面刷新
    • $set 添加数据属性,必须在onInit函数中使用,用法:this.$set('key',value)
    • $delete 删除数据属性,如果在onInit函数中使用,用法:this.$delete('key')

    六、元素属性方法

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

    • $set 添加数据属性,用法:this.$vm('id').$set('key',value)
    • $delete删除数据属性,用法:this.$vm('id').$delete('key')
    • $on 在当前页面注册监听事件, 可监听$emit()$dispatch()$broadcast()等触发的自定义事件,不能用于注册组件节点的事件响应
    • $off 移除事件监听,参数 fnHandler 为可选,传递仅移除指定的响应函数,不传递则移除此事件的所有监听
    • $emit 触发当前实例监听事件函数,与 $on() 配合使用

    七、页面设计

    布局和尺寸

    • 采用border-box 模型且不支持 box-sizing 属性
    • 目前仅支持长度单位px%
    • 设计稿1px / 设计稿基准宽度 = 框架样式1px / 项目配置基准宽度(项目配置基准宽度:/src/manifest.jsonconfig.designWidth 的值,默认750)

    CSS

    • 可以使用内联样式、tag选择器、class选择器、id选择器来为组件设置样式
    • 仅可以使用并列选择、后代选择器、子代选择器
    • 支持@import引入外部样式、内联样式、行内样式
    • 颜色值不支持缩写,伪类支持不完全(支持:disabled,:checked,:focus等)

    八、组件

    组件为文本容器组件,其它组件不能直接放置文本内容

    : 和 HTML 一样

    支持样式 flex-direction, flex-wrap, justify-content, align-items, align-content

    : 气泡框

    • 支持属性 targetplacement
    • 支持样式 mask-color
    • 支持事件 visibilitychange
    • 自组件只能是

    : 下拉刷新

    • 支持属性 offsetrefreshing
    • 支持样式 background-colorprogress-color
    • 支持事件 refresh

    : 富文本编辑器

    • 支持属性 type(值为 html)
    • 支持div样式, height 无效
    • 不支持子组件

    更多详情 https://doc.quickapp.cn/widgets/div.html

    九、页面切换和参数传递

    9.1 参数传递

    传递方法1

    标签配合 queryString 传递参数, 这个和前端一致

    跳转页面
    
    
    携带参数key2跳转
    

    传递方法2

    // 导入模块
    import router from '@system.router'
    

    通过 router 接口:router.push(), router.replace(), 接受一个如下结构的对象,用法这个和前端 router 一致。

    {
      url: '/src/home/index.html',
      params: { key: 2333 /* 需要传递的参数 */ }
    }
    

    接收参数

    上述2种传递参数的方法,其接收方法一致,在接收参数页面的 protected对象中获取即可(可设置默认值)

     export default {
        protected: {
          key: ''
        },
        onInit () {
          this.$page.setTitleBar({ text: '接收参数' })
    
          // js中输出页面传递的参数
          console.info('key: ' + this.key)
        }
      }
    

    回传参数

    开发者可能会遇到需要在页面之间回传参数的需求

    • 假设存在页面A和页面B,先从页面A跳转至页面B,然后从页面B返回到页面A时,需要传递参数
      = 此时,组件a和接口router传参不能满足需求,可以借助于app级别的对象:this.data

    页面A实现代码如下

    
    
    
    
    
    

    页面B实现代码如下:

    
    
    
    
    
    

    9.2 页面间通信

    https://doc.quickapp.cn/framework/script.html

    会利用到一个构造函数 new BroadcastChannel(string), 它接受一个字符串参数,作为实例的频道名称。它的实例具有以下属性和方法

    • name 频道名称,区分不同的消息频道(注意:不同频道之间不可通信)。
    • postMessage 用于在当前频道中广播消息
    • onmessage 订阅消息。在频道中接收到广播消息之后,会给所有订阅者派发消息事件
    • close 关闭当前的频道

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

    • type message
    • data 接收到的消息内容

    十、组件通信

    父组件到子组件

    • 子组件通过 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

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

    http://hapjs.org/app//[path][?key=value]
    https://hapjs.org/app//[path][?key=value]
    hap://app//[path][?key=value]
    
    • package: 应用包名,必选
    • path: 应用内页面的path,可选,默认为首页
    • key-value: 希望传给页面的参数,可选,可以有多个

    从传统网页调起需引入以下脚本

    
    

    触发原生组件事件

    通过$emitElement()完成事件的动态触发

    • $emitElement(evtName, evtDetail, id)

    可以触发指定组件id的事件,通过evt.detail获取传递的参数;该方法对自定义组件无效

    
    
    
    
    
    

    十三、打包及发布

    13.1 编译工具

    1)编译打包工程

    • 在工程的根目录下运行
    npm run build
    
    • 编译后的工程目录在/build
    • 生成的应用路径为/dist/.rpk

    2)增加 release 签名

    通过 openssl 命令等工具生成签名文件private.pemcertificate.pem,例如:

    https://doc.quickapp.cn/tools/compiling-tools.html

    opensslreq -newkey rsa:2048 -nodes -keyout private.pem -x509 -days 3650 -outcertificate.pem
    

    在工程的 sign 目录下创建 release 目录,将私钥文件 private.pem 和证书文件 certificate.pem 拷贝进去

    3)发布程序包

    发布程序包前需要增加release签名,然后在工程的根目录下运行

    npm run release
    
    • 生成的应用路径为/dist/.release.rpk
    • 如果需要临时使用 debug 签名,可以使用
    npm run release -- --debug
    

    13.2 IDE发布

    • 1)生成证书。点击快应用面板的【生成证书】按钮, 按提示输入相关信息
    • 2)生成发布用 RPK。点击【发布 rpk包】按钮, 生成成功的话会弹出对应的文件夹

    image

    十四、快应用分享专题

    快应用简介_第7张图片

    image

    十五、上传到快应用中心审核

    快应用注册账号 https://www.quickapp.cn/docCenter/post/74

    快应用简介_第8张图片

    image.png

    十六、一些问题

    • 资源文件、代码文件的命名均不能含有中文,命名不能连续使用下划线,否则打包发布时会包解析失败,导致无法上传
    • 自定义属性名不能采用驼峰命名,否则值永远是 undefined
    • show 属性并不好用,没起什么作用
    • 类似 onInit 等等函数是页面生命周期,不是组件生命周期,不会因为组件状态变化而执行
    • display类型只有 flexnone
    • 子盒子不能将父盒子撑高
    • 不遵循盒子模型,类似但不完全等同于 border-box
    • 不能全局引用样式,只能在每个page中使用@import引入
    • 逻辑控制块,仅支持forif/elif/else,不支持show条件渲染
    • justify-content属性,在快应用官方开发环境中,目前不支持space-around
    • 针对于目前vscode插件hap-extension不支持sass语法,可以把.scss单独存储,通过style.src引入到.ux中,同时方便管理
    • 当前自定义组件不支持传入的propsfunction
    • 快应用中很多 html都不能用,比如没有 p,h1~h2 等,因为它只是模拟了部分 html标签,最终会转化成原生组件
    • 只能使用 aspantextlabel 放置文本内容
    • position 只能是 fixednone
    • 长度单位只有 px%

    十七、快应用开发资源

    官方资讯

    • 十大手机厂商共推快应用标准,发布会完美落幕
    • 教你尝鲜「快应用」!体验秒开,如丝般顺滑!
    • 快应用+小程序,99%的Android程序员即将失业!

    官方文档

    • 入门教程
    • 接口文档
    • 框架文档
    • 官方网站
    • 官方论坛
    • toolkit
    • 编译工具
    • 调试工具

    工具

    • Quix - UI for Quick App
    • 基于weui开发的quickapp
    • 快应用转换工具 - 小程序转快应用
    • flyio - 支持快应用的http网络库

    示例

    • Gank客户端
    • 内涵车站APP
    • wanandroid快应用
    • quickapp-douban
    • 快应用版Wechat

    插件

    • Vscode Hap Extension--轻应用语法高亮插件
    • Vscode 一个基于vscode应用于‘快应用’语法高亮
    • Vscode Quick App美化代码

    教程

    • 对标小程序 ? "快应用"开发入门指南 By鸿洋
    • 快应用快速入门教程 by大大花猫
    • 快应用 QuickApp--入门指北
    • 快应用简明使用指引
    • 快应用QuickApp--HelloWorld体验
    • 快应用快速入门教程 by五个半柠檬(SF)

    讨论

    • 「快应用」项目?会对微信小程序以及 App 生态有何影响?(知乎)
    • 如何看待国内几家硬件厂商联合鼎力打造的快应用?(知乎)
    • 九大厂商联合推出「快应用」,围攻微信?(知乎)
    • 腾讯“小程序”与手机“快应用”之战(知乎)

    分享

    • 饿了么快应用初体验
    • 是前端还是Android?快应用 快速入门与初步分析
    • 快应用初体验
    • [前端工坊]快应用-技术调研
    • 快应用发起进攻第一枪!小米直达服务正式更名快应用
    • 手机厂商和开发者为何看好快应用新生态
    • 魅族体验快应用:免安装,快速触达你要的服务
    • 资源汇总 快应用开发常见问题和技术帖子汇总(持续更新)
    • 快应用API Demo 集合 QuickAPP



    作者:poetries
    链接:https://www.jianshu.com/p/94fc14897c9f
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    你可能感兴趣的:(Programer,life)