分享人:夏燕飞
近期因为需求与bug比较多,因此有些拖更了。非常抱歉,那么今天的干货开始了。。。
该篇为“快应用”第一篇。欢迎大家阅读!
自快应用问世,到现在也已经有一年多了。快应用和微信小程序类似。都是用户体验介于网页与原生APP之间的新型应用模式。微信小程序我想大家都用过,但是快应用却不一定。首先微信小程序问世要比快应用早一年,而且靠着微信的用户社交粘性和闭环,以及小程序支持安卓与ios端。使得小程序到目前为止,依旧发展得比快应用好。但未来不一定。
快应用可以说是9大手机厂商为了不使微信小程序抢占应用流量而出现的吧。
毕竟微信小程序是以微信为载体,是一种二级应用,打开小程序前必须要打开微信的占用内存。而快应用是手机厂商出品的,不需要以某个为载体,直接操作系统打开,属于一级应用。可以直接调用底层系统功能。其实厂商可根据其优势,提升手机的原生性能,使得其强于微信小程序的体验也是可以的,不过这得待后期发展了。
现在我们从技术角度来说说开发快应用吧!
项目结构
按快应用脚手架工具初始化的项目基本能满足一般的项目开发需求了。比如现在初始化一个
hap init hiquick
项目:
得到一个如下结构的项目目录:
├── sign //rpk包签名模块
├── src
│ ├── Common //公用的资源和组件文件
│ ├── Demo //页面目录
│ │ └── index.ux //页面文件,可自定义页面名称
│ ├── app.ux //APP文件,可引入公共脚本,暴露公共数据和方法等
│ └── manifest.json //项目配置文件,配置应用图标、页面路由等
其中 Demo 目录即是一个页面目录,包含一个 ux 后缀的页面文件。项目构建运行之后,还会产生 build/、dist/ 两个目录。build 是打包构建后生成的 js 文件、dist 则是 rpk 安装包。
在我们实际项目中由于业务比较复杂,会创建很多页面,这样平铺在根目录下,造成文件夹过多不易管理维护。
于是我们新建一个文件夹 pages 专门存放页面,这样项目结构就变成了:
├── sign
├── src
│ ├── common //公用资源、全局配置
│ ├── components //公用组件
│ ├── pages
│ │ ├── index //页面目录
│ │ │ └── index.ux //页面文件
│ │ └── login
│ ├── app.ux
改造后的目录结构更直观、简洁。不过要记得去修改默认的页面路由配置:router.pages、display.pages 两项的页面键值要改和页面路径一致。如这里首页的配置就是 pages/index。
除了新增 pages 目录,还新增了 components 文件夹和更改 common 文件夹的用途。
新增的 components 文件夹专门存放公用的组件文件,而 common 则专门用来存放公共资源、工具方法和全局配置等文件。这样使得目录的功能区分更明白了,也为后面的代码复用作好了基础准备。
其中全局配置的配置项皆以模块化输出,既对变量有一个统一的维护管理,也方便在业务直接引入调用,一举两得,非常高效。
页面划分
上面已经说了我们为所有页面专门建立了一个 pages 文件夹。从中可以看出应用中的所有页面是平级划分的。虽然在业务逻辑上可能存在父子关系,但实际页面没必要分出从属,那样只会增加页面关系的复杂度。
但这里有一个特殊页面还是设计了父子关系。这么做也恰恰想表明页面间从属关系。这就是 pages/index 页面,为了避免概念混淆,这里先称之为索引页。因为它正是起着索引导航作用的,并不是常规意义上的首页。
通常,一个APP的界面是这样的:
在界面底部会有一个导航菜单栏,叫做 TabBar,然而快应用并没有这种组件。虽然利用页面路由可以做导航,但效果并不理想,切换过来的页面都需要重新加载。由于页面中已经使用了 tabs 组件,使用tabs组件实现也不可行。
剩下就需要自己动手打造了。既要实现页面导航,又要实现页面缓存的功能。
简要分析下组件的设计思路。
在单页内实现不同页面的切换,功能相当于一个Tab。
功能区分为tab标签栏和tab内容区。
标签的项目不能写死,要可以自由扩展。
每个标签对应的页面以组件形式引入。
在 index.ux 页面需要引入 TabBar 页面组件。作为子组件,为方便管理,我们把这些子页面组件作为子文件夹放在 index/ 下管理维护,一目了然地表明页面的从属关系,整体项目的页面切分工作也完成了。
│ ├── pages
│ │ ├── index //索引导航目录
│ │ │ ├── subpages //子页面目录
│ │ │ │ ├── featured //子页面
│ │ │ │ │ └── index.ux //子页面组件文件
│ │ │ │ └── member
│ │ │ │ └── index.ux
上面 TabBar 的功能设计还忽略一点,就是子页面组件更新的问题。为此做了监听标签切换及页面 onShow 事件触发组件更新的处理,这里不做详细说明。
公共代码
下面着重来说下公共代码部分,公共代码及组件化向来都是项目中的重点部分,这部分作好了,会使得项目代码越写越少,越写越高率。相反,如果这部分没有做好,不仅会让项目代码变得一团糟,不断地重复工作,还极有可能会埋下一些潜在的危险。
比如项目中公用的一个参数,分别写在各个地方,等到需要更改时,很可能改了一个地方而忘了另一个地方,等到出错还不容易排查问题出在哪里。如果统一在一处配置好,其它所有地方只引入这个配置,则会从根本上规避这个低级错误。
当然这只是做好公共管理的优点之一。
公共代码和组件化开发应该深入到任何项目的任何角落,应该时刻保持这种意识。
在快应用项目中我们将公共资源、公共代码都放在了 common 文件夹下。包含全局基础样式文件、图片资源、配置项文件、和工具方法。
配置项文件 config.js 集中管理全局使用的常量和API接口地址,并对依赖不同域名环境下的配置项做自动切换处理。
工具方法 utils.js 将可复用的工具函数方法抽象出来,并以模块化形式导出,方便其它模块中按需引入,而不需要在不同的地方重复地写同一个工具方法了。
再来说说组件化,这也是项目开发中的重点。
组件化应该是在项目一开始就需要着手考虑的事情,原则上在交互稿评审阶段就需要开始了。分析出哪些部件可以提取抽象出公共组件。这样多人协作的项目中,共同开发将变得非常有效率。
快应用项目目前拆分出的公共组件有图文展示组件、TitleBar页面标题栏组件、错误状态提示组件、章节目录组件等(排除快应用框架自身的组件)。
TitleBar组件实现自定义的头部标题样式,在默认的标题栏不满足需求时可以使用该组件实现。
错误状态提示也是复用较高的组件,在处理无网络、暂无数据等状态下都可以直接引用。大大减少代码的重复开发工作。
体验、性能的优化
除了以上的改造优化外,性能的优化也是无法绕开的。开发过程中除了基本该做的优化要做到之外,能发现的性能问题也应该寻找方案解决。当然如果时间不允许或者暂无方案解决则另当别论。
那快应用项目中所做的性能优化工作列举几点如下。
TabBar页面导航优化
前面说了TabBar的设计思路,也提到了设计的意义,涉及的主要优化有:
按需加载,首次只加载默认标签页。
页面缓存,避免切换时页面的重复加载。
返回键退出应用,避免路由链路过长。
TabBar配置的标签项,默认只会加载其中一个页面,这个初始展示的页面由配置项 currentTabName 决定。点击其它标签后,才加载对应的页面。页面加载完成后,再次切换标签,已加载的页面则是显示或隐藏,不会重新加载渲染。提高了用户使用体验的同时,也节约了没必要的网络请求。
前面也提到直接使用路由跳转也是可以实现类似的效果。使用路由来实现,技术复杂度会大大降低,但使用感受也比较糟糕。除了切换时页面重复加载渲染之外 ,页面栈也会随着不断切换而加大,这时如果想返回则会走很长的链接。虽然可以通过设置replace路由替换规避,但页面重复加载渲染是避免不了的。
快应用与web组件的通信优化
快应用的订购环节由于技术限制,需要引用web组件来加载HTML页面实现订购。交易环节事关重大,功能上容不得半点差错,性能上要保证稳定可靠。技术上涉及到快应用与HTML之间的通信。而在调试过程中却发现了通信机制的一个Bug。
起始在开发中发现web组件存在通信不稳定的问题,初步判定为可能页面还未加载完成。为保证通信的可靠性,我们在页面加载完成的回调事件 onpagefinish 中发起通信。然而web组件会自动触发两次 onpagefinish 回调。原因暂时不明确,问题也和官方沟通过。总之这会造成HTML中监听通信的请求也发送两次。于是想办法去阻止web组件二次触发回调事件。
在 onpagefinish 事件中设置回调状态,如果判断状态为true 则表明web已经完成加载,就不用再次发起通信。这样处理之后,发现不会再二次触发了,而且在调试和测试过程中观察通信成功率达到100%。
总结
项目技术选型、架构设计及优化工作都是开发过程的重要因素。一个合理的项目架构会让开发过程变得省力有趣。相反则会低效,既影响开发体验也对优化及后续维护、优化不利。
如果各位对我们有什么意见或建议,欢迎回复我们哦。
觉得不错的童鞋们请记得点赞、转发、关注三连哦!!!
从现在起我们的公众号已改名为“大前端早读”内容范围围绕大前端,也开启系列篇,更多原创文章请关注我们,
并点击内容系列--原创篇,学习更多: