如何从 HTML5 快速转型快应用?
2018年3月份,由小米,中兴,华为等10家厂商成立了快应用联盟,共同发布了快应用的标准。自此我们可以采用一套标准去开发应用,而无缝的运行在各个手机厂商上。一次开发,一次上传,自动分发到所有联盟厂商的设备。
根据快应用官方的说法,快应用是采用前端的技术栈来开发的,这篇文章以一个前端开发者的角度,来介绍怎么开发快应用,快速入门快应用的开发。
什么是快应用?
快应用是基于手机硬件平台的新型应用形态,标准是由主流手机厂商组成的快应用联盟联合制定;
快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放;
快应用具备传统APP完整的应用体验,无需安装,即点即用。
快应用的技术特点包括:
采用前端技术栈,运行和开发效率高,学习成本低,代码可以复用;
原生渲染能力,功能完备,体验等同于应用,资源消耗小。
从上面我们可以了解到:
1、快应用不是HTML5,但是可以用前端已有技术栈直接上手开发;
2、快应用是原生渲染,有着比H5更加完备的功能及原生体验;
3、快应用即点即用,无需安装。
快应用 vs HTML5开发
首先,我们来回顾一下,在Web项目中是怎么进行开发的?
简单的说下,可以分为以下9个步骤:
拿到PSD设计图;
切图;
将PSD转成HTML;
写JS业务逻辑;
mock数据,自测;
与后端联调;
提交测试;
上线;
迭代与优化。
如下图所示:
做过前端的同学对这个步骤应该很熟悉了,快应用的开发步骤和这差不多,主要有2点差别,我们来比较一下:
HTML5开发是基于浏览器的,直接写完后在浏览器下就可以运行,看效果。但是快应用开发是基于NodeJS环境的,所以我们开始需要搭建一下开发环境;
在将PSD转成HTML的时候,快应用提供了一个脚手架,当然HTML5的一些项目里面也有脚手架,比如Vue、React项目,官方都提供了一个脚手架,方便开发者进行开发。
如下图所示,下面是快应用的开发过程:
下面从搭建环境、hap-toolkit的使用、静态页面书写(PSD转成HTML)、JS业务逻辑的书写、调试这5个方面来说说如何开发快应用。其他的步骤都是HTML5开发常见的步骤,和HTML5一样,直接迁移过来就行。
1、搭建开发环境
快应用开发是基于前端技术栈的,官方团队提供了基于NodeJS的开发环境,可以参考官网的详细教程。
主要是:
NodeJS(推荐 Node 8以上版本);
hap-toolkit 编译工具;
快应用调试器和快应用预览版(方便调试和查看效果)。
当然快应用官方也提供了IDE,也可以直接安装一个IDE。
2、hap-toolkit的使用
安装好hap-toolkit后,可以在控制台输入hap -v 看看当前的版本。
当前的最新版本是0.1.1。
下面是hap-toolkit的一些常见用法:
具体可以参考:https://doc.quickapp.cn/tools/toolkit-tools.html。
3、静态页面书写
快应用提供了组件和指令,方便PSD转化成HTML。
01.组件
快应用中组件与Vue中组件类似,一个快应用,可以组织为一个嵌套的组件树,如下图所示:
组件分类:
原生组件;
自定义组件。
当一个页面的业务逻辑变得复杂时,就需要将页面拆成多个模块,完成解耦。所以,快应用提供了自定义组件的能力,定义自定义组件与开发页面一致。
text、div等为原生组件,由各平台 Native 底层渲染;
自定义组件是一个开发者编写的组件,使用起来和 Native 一样,最终按照组件的<template>来渲染,页面也是一种自定义组件;
自定义组件比页面组件的不同之处在于多了一个props属性,用于声明该组件可接受的外部数据传递,props是一个数组,数组中每个元素是暴露的属性名称,如果属性名称使用驼峰定义,如:prop2Object,那么在外部传递数据时请使用-连接,如:prop2-object;
引入自定义组件的方式为通过 <import> 标签引入,如: <import name="comp-part1" src="./part1"></import>;
父子组件之间可以通过事件进行通信,兄弟组件之间通过 Publish/Subscribe 模型来完成通信,详情请见文档。
02.指令
框架指令是框架为组件定义的特殊属性,以及框架提供的特殊组件,用于自定义页面DOM结构渲染逻辑。
指令主要包含:
注意:
for 循环自定义变量表示 for 指令的数组索引和数组元素时,变量名不可以用$或_开头;
if/elif/else 节点必须是相邻的兄弟节点。
4、JS业务逻辑的书写
快应用的JS是采用ES6语法标准的,支持ES6的特性。这里主要讲2个方面:生命周期和事件机制。
01.生命周期
生命周期概念为现代前端开发的重要基础,快应用里,页面的生命周期指的也就是ViewModel的生命周期,整个页面生命周期如下:
APP 中可以同时运行多个页面,但是每次只能显示其中一个页面。
02.事件机制
与HTML5一样,快应用里面也提供了事件机制。
on用于监听自定义事件;off移除对应的事件监听;
$emit()、 $dispatch()、 $broadcast()等触发事件,其中$dispatch()为向上传递,$broadcast()为向下传递;
原生组件支持一系列事件,如通用事件、组件专有事件,通过on+事件名称作为组件属性,来监听事件(如:focus事件,可以用 onfocus 属性监听)。
5、调试
不同于传统前端开发,快应用运行在厂商联盟的手机上。因此,官方提供了调试工具。
开发者可通过快应用调试器来调试快应用。类似Chrome的调试工具。快应用调试目前支持 chrome devtools 中的elements、console、source、network等模块。
使用chrome devtools进行调试:
性能优化
性能优化是前端永恒的主题。性能优化包括两个大类:
通用的解决方案,这类具有普适性;
与具体组件结合的解决方案,如:组件级别的懒加载,甚至利用组件本身特性完成优化。
建议开发者了解性能优化的常见方案,提升应用性能。
1、简化ViewModel的数据
在ViewModel的定义中,属性public、protected、private 主要承担数据驱动的数据定义与改造功能,会对赋值的数据中每个属性进行递归式的定义。因此,属性个数的定义越少越好,尤其是数组类型数据,建议过滤不需要用到的对象属性。
示例如下:
如果页面仅需要用到 list 中每个 item 的 userId、orderName 属性的话,则仅赋值这两个属性到ViewModel数据中,过滤掉非相关属性。
// 模拟fetch请求返回的数据
const orderList = [
{
userId: '123',
orderName: 'XX产品',
userName: '张三',
shoppingList: [
{
productId: '001',
productLink: 'http://xxx',
productShop: {
ownerId: '2390',
ownerName: 'XXX店铺'
}
}
]
},
{
// ...
}
]
export default {
private: {
list: []
},
onInit () {
// 返回页面中需要的对象属性,过滤无用的对象属性
this.list = orderList.map(item => {
userId: item.userId,
orderName: item.orderName
})
}
}
2、合理使用后代选择器
框架支持 CSS 中的后代选择、支持 less 预编译,方便开发者开发,提升代码可维护性。然而,过多的使用后代选择器,也会在节点匹配上带来性能损耗,尤其是当一个节点满足多个选择时。
优化建议如下:
避免使用组件名称(tag 标签名称)作为后代选择的最后一项匹配规则,如: .doc-page #shop text { ... };否则每个 text 组件渲染时都会遍历匹配一次;
减少后代选择的层级数量,层级越深,单次匹配耗时越长,如:.class1 .class2 .class3 .class4 .class5 .class6 { ... };
后代选择中最后一条匹配规则的定义名称尽量唯一,如:.doc-page #shop .shop-item .shop-name-full { ... }。
3、使用懒加载
懒加载是一项通用的优化手段,传统 H5 页面中的图片懒加载,指的是页面即将滚动到屏幕可视区域时,才加载资源,渲染页面。
在框架中,也可以使用懒加载技术:为了加快页面可视区域的渲染,可以通过指令或者事件触发等手段推迟不可见区域的渲染。
参考文档:
快应用开发教程:
https://doc.quickapp.cn/tutorial/
sample项目:
https://github.com/quickappcn/sample
热 文 推 荐
☞ 拼多多:“优惠券Bug属网络诈骗”;抖音多闪上架 App Store;任正非不知谁是接班人 | 极客头条
☞ JavaScript 能写一切?Python 不服:盘它!
☞ 惊慌 Android!使用 3D 打印的头像可破解多款手机
print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"