这一篇主要讲一下H5页面中的关键功能点如何在小程序、app(原生客户端)以及浏览器端进行的差异化处理,我们这个项目属于电商类,涉及用户和交易整个流程,包含 注册登录模块、收货地址模块,支付模块,下面分别讲解。
注册登录属于核心功能,尤其是涉及到购买相关,既然是跨端的方案,我们首先要想到的是充分利用好页面所在的运行环境。
浏览器端
在浏览端是比较简单的,只需根据现有后端提供的基于web cookie的方案开发独立的登录组件即可,这个项目中我们封装了全局适用的登录组件,在项目的启动文件中(App.vue)一次性引入并通过eventBus.on 监听登录事件(login),在后续的子页面里需要执行登录操作的地方触发此事件即可唤起登录界面。登录成功后继续完成后续动作。
原生app端
在原生app环境下,H5页面运行在webview内,为了达到交互体验最佳和与客户端同步登录状态,需要调起原生的登录界面,因H5页面中会通过api检查登录状态,剩下的则需要跟客户端约定本地交互协议通过JsBridge方案实现双向信息传递。具体是:可约定openLogin 协议,携带必备参数,如 returnUrl 用于客户端完成登录动作后的登录状态同步和页面刷新,还可以传递callback 函数,由客户端执行js方法 来完成后续的操作。这里讲到的JsBridge 有不少开源的框架,技术非常成熟,但是具体的协议制定和封装需要由自己来完成,项目中我们封装了一套协议集,可全局引入来使用。最后也建议,在跟客户端约定协议时要充分考虑到可复用性,尽量不要因为一个私有功能的实现来约定协议。
小程序端
该项目有独立的小程序入口,所以部分模块是以原生的方式实现的。H5运行环境类似客户端原生app,都是开启webview 加载H5页面,不过区别在于无法像原生客户端那样约定协议来完成功能开发。在小程序端(这里以微信小程序为例)为了使用小程序自带的授权登录功能,我们专门开发了原生的登录模块,这个登录模块可以实现原生的:授权用户信息--> 授权手机号--> 一键注册登录功能,能很好地提升交互体验。因为是独立的登录模块,完成登录后,会执行返回动作,在H5所运行的webview 中 onShow 事件函数监听并校验是否登录成功,然后执行后续页面动作。
收货地址模块在各端的实现首先考虑到的是便利性和复用现有模块,如,小程序端开发独立原生的地址组件,在组件内可直接使用例如微信提供的一键获取用户地址功能。app端则是复用原生的地址模块,同样通过JsBridge 约定协议完成地址选择和添加。浏览器端封装独立组件即可。
这里讲到的支付模块属于收银台相关,同样是核心功能点,在各端都有自己的实现方案,下面分别讲述。
浏览器端
基于浏览器的收银台模块主要包含市面上常用的支付渠道如:支付宝,微信等。这里存在两种支付流程。
基于H5流程的支付,也就是说在收银台页面根据用户选中的支付方式外跳到第三方支付页面,完成支付并返回。基于scheme协议的支付流程,收银台页面通过执行对应支付渠道的scheme协议地址来拉起手机上安装的支付app,完成支付并返回。原生app端
在原生app中已内置了第三方的支付sdk,并且完成了独立封装,交互体验更优于浏览器端,通过约定交互协议,由H5发起支付唤起支付控件即可。这里需要注意处理好异常状态的捕获,在H5页面中做好兜底处理。
小程序端
小程序相比上面两端有着明显的差异,关键在于需要开发小程序原生的支付界面来完成支付,因为只有在原生页面才有权限使用支付api,具体流程是:完成下单动作 ---> 组装支付参数---> 跳转到小程序支付界面---> 调起小程序支付api---> 完成支付---> 重定向到H5支付结果页。
在各家的小程序平台中,对于支付api的功能存在差异,比如,微信只有微信支付一种方式,不需要选择支付方式。百度小程序则是封装了一套收银台界面,可选择多种支付渠道。需要我们根据平台特性去适配开发。
以上主要讲述了在这个项目中如何进行的差异化处理,其核心是为了提升用户体验,降低开发成本,这是我在这个项目的实现方案,也许你会有更好的思路,欢迎跟我一起讨论。最后给大家附上我在项目中用到的环境检查工具方法,希望对你有帮助。
// Browser environment sniffing const UA = window.navigator.userAgent.toLowerCase() // 获取运行环境UA const isIE = UA && /msie|trident/.test(UA) // IE环境 const isIE9 = UA && UA.indexOf(msie 9.0) > 0 // IE9 const isEdge = UA && UA.indexOf(edge/) > 0 // windows的Edge浏览器 const isAndroid = UA && UA.indexOf(android) > -1 // 安卓环境 const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA) // IOS环境 const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge // 为chrome const isAliMiniP = UA && UA.indexOf(alipayclient) > -1 && UA.indexOf(miniprogram) > -1 // 支付宝小程序 const isBaiDuMiniP = UA && UA.indexOf(swan-baiduboxapp) > -1 // 百度小程序 const isTouTiaoMiniP = UA && UA.indexOf(toutiaomicroapp) > -1 // 头条小程序 const isWXMiniP = (UA && UA.indexOf(micromessenger) > -1) && (UA.indexOf(miniprogram) > -1 || window.__wxjs_environment === miniprogram) // 微信小程序 const isWXWeb = (UA && UA.indexOf(micromessenger) > -1) && !isWXMiniP // 微信web const isMiniP = isBaiDuMiniP || isAliMiniP || isWXMiniP || isTouTiaoMiniP // 小程序环境 const isMobileBrowser = !isMiniP && !isWXWeb && !isKFZApp && (isIOS || isAndroid) // 手机浏览器(非小程序) const isPCBrowser = !isMiniP && !isWXWeb && !isKFZApp && !isIOS && !isAndroid // pc浏览器 const platform = { UA, isIE, isIE9, isEdge, isAndroid, isIOS, isChrome, isAliMiniP, isBaiDuMiniP, isTouTiaoMiniP, isWXMiniP, isWXWeb, isMiniP, isMobileBrowser, isPCBrowser } export default platform;