前言

在框架规划时,就有提到过这个框架的一些常用功能需要支持H5环境下的调用,也就是需要实现API的多平台支撑

为什么要多平台支撑?核心仍然是复用代码,比如在微信下,在钉钉下,在quick容器下,

如果没有多平台支撑,那么quick.ui.alert只能用于quick容器下,钉钉和微信下就得分别用其它代码实现,

代码复用率低,如果实现了多平台支撑。那么三个平台中同一个功能的代码则是一样的。

什么样的多平台支撑

当然了,本框架实现的多平台支撑和一般框架的有点区别。

一般的框架中支持多个平台更多的是一个polyfill,譬如

// 假设以前不支持h5
const oldToast = quick.ui.toast; quick.ui.toast = function(...) {
if (os.h5) {
// 做一些h5中做的
...
} else {
oldToast(...);
}
};

这就是垫片实现,如果是新的环境,用新的实现,否则用老的实现

而__本框架中的多平台实现是直接内置到了框架核心中__,也就是说框架本身就支持多平台API的设置

quick.extendModule('ui', [{
namespace: 'toast',
os: ['h5'],
defaultParams: {
message: '',
},
runCode(...rest) {
// 定义h5环境中的做法
...
},
}, ...]; quick.extendModule('ui', [{
namespace: 'toast',
os: ['quick'],
defaultParams: {
message: '',
},
runCode(...rest) {
// 定义quick环境中的做法
...
},
}, ...];

在框架内部定义API时,不再是直接的quick.ui.alert = xxx,而是通过特定的API单独给某个环境下定义实现

而且,框架中的定义,每一个API都是有quickh5环境下的实现的。

多平台支撑的核心

从上述的介绍中也可以看到,多平台支撑主要是前端的实现,与原生API,原生API在这里面只能算一个环境下的实现

核心就是基于:Object.defineProperty,重写set和get

Object.defineProperty(apiParent, apiName, {
configurable: true,
enumerable: true,
get: function proxyGetter() {
// 需要根据不同的环境,返回对应下的内容
...
},
set: function proxySetter() {
// 可以提示禁止修改API
},
});

本框架中的多平台实现代码可以参考源码,这里不赘述,下文中会介绍如何简单的实现一个多平台支撑API

实现一个多平台支撑API

我们先预设最终的结果:

quick.os.quick = true;
quick.ui.alert('hello'); // quick-hello quick.os.quick = false;
quick.ui.alert('hello'); // h5-hello quick.ui.alert = 11; // 提示:不允许修改quick API

那么要达到上述的要求,应该如何做呢?

写一个雏形

最简单的,先假设这些实现都已经存在,然后直接基于defineProperty返回

function alertH5(message) {
alert('h5-' + message);
}
function alertQuick(message) {
alert('quick-' + message);
}
const quick = {}; quick.ui = {};
quick.os = {
quick: false,
}; Object.defineProperty(quick.ui, 'alert', {
configurable: true,
enumerable: true,
get: function proxyGetter() {
// 需要根据不同的环境,返回对应下的内容
if (quick.os.quick) {
return alertQuick;
} else {
return alertH5;
}
},
set: function proxySetter() {
// 可以提示禁止修改API
alert('不允许修改quick API');
},
});

那么,它的调用结果是

quick.os.quick = true;
quick.ui.alert('hello'); // quick-hello quick.os.quick = false;
quick.ui.alert('hello'); // h5-hello quick.ui.alert = 11; // 提示:不允许修改quick API

虽然效果和预设的一样,但是很明显还需优化完善

增加拓展API的方法

拓展方式的定义如下

const quick = {};

quick.os = {
quick: false,
};
/**
* 存放所有的代理 api对象
* 每一个命名空间下的每一个os都可以执行
* proxyapi[namespace][os]
*/
const proxysApis = {};
// 支持的所有环境
const supportOsArray = ['quick', 'h5']; function getCurrProxyApiOs(currOs) {
for (let i = 0, len = supportOsArray.length; i < len; i += 1) {
if (currOs[supportOsArray[i]]) {
return supportOsArray[i];
}
} // 默认是h5
return 'h5';
} // 如获取quick.ui.alert
function getModuleApiParentByNameSpace(module, namespace) {
let apiParent = module;
// 只取命名空间的父级,如果仅仅是xxx,是没有父级的
const parentNamespaceArray = /[.]/.test(namespace) ? namespace.replace(/[.][^.]+$/, '').split('.') : []; parentNamespaceArray.forEach((item) = >{
apiParent[item] = apiParent[item] || {};
apiParent = apiParent[item];
}); return apiParent;
} function proxyApiNamespace(apiParent, apiName, finalNameSpace) {
// 代理API,将apiParent里的apiName代理到Proxy执行
Object.defineProperty(apiParent, apiName, {
configurable: true,
enumerable: true,
get: function proxyGetter() {
// 确保get得到的函数一定是能执行的
const nameSpaceApi = proxysApis[finalNameSpace]; // 得到当前是哪一个环境,获得对应环境下的代理对象
return nameSpaceApi[getCurrProxyApiOs(quick.os)] || nameSpaceApi.h5;
},
set: function proxySetter() {
alert('不允许修改quick API');
},
});
} function extendApi(moduleName, apiParam) {
if (!apiParam || !apiParam.namespace) {
return;
} if (!quick[moduleName]) {
quick[moduleName] = {};
} const api = apiParam;
const modlue = quick[moduleName];
const apiNamespace = api.namespace;
const apiParent = getModuleApiParentByNameSpace(modlue, apiNamespace);
// 最终的命名空间是包含模块的
const finalNameSpace = moduleName + '.' + apiNamespace;
// 如果仅仅是xxx,直接取xxx,如果aa.bb,取bb
const apiName = /[.]/.test(apiNamespace) ? api.namespace.match(/[.][^.]+$/)[0].substr(1) : apiNamespace; // 这里防止触发代理,就不用apiParent[apiName]了,而是用proxysApis[finalNameSpace]
if (!proxysApis[finalNameSpace]) {
// 如果还没有代理这个API的命名空间,代理之,只需要设置一次代理即可
proxyApiNamespace(apiParent, apiName, finalNameSpace);
} // 一个新的API代理,会替换以前API命名空间中对应的内容
const apiRuncode = api.runCode;
const oldProxyNamespace = proxysApis[finalNameSpace] || {}; proxysApis[finalNameSpace] = {}; supportOsArray.forEach((osTmp) = >{
if (api.os && api.os.indexOf(osTmp) !== -1) {
// 如果存在这个os,并且合法,重新定义
proxysApis[finalNameSpace][osTmp] = apiRuncode;
} else if (oldProxyNamespace[osTmp]) {
// 否则仍然使用老版本的代理
proxysApis[finalNameSpace][osTmp] = oldProxyNamespace[osTmp];
}
});
} function extendModule(moduleName, apis) {
if (!apis || !Array.isArray(apis)) {
return;
}
if (!quick[moduleName]) {
quick[moduleName] = [];
}
for (let i = 0, len = apis.length; i < len; i += 1) {
extendApi(moduleName, apis[i]);
} } quick.extendModule = extendModule;

上述代码中增加了些复杂度,有一个统一管理所有代理调用的池,然后每次会更新对于环境下的代理

基于上述的方式可以如下拓展对于环境下的API

quick.extendModule('ui', [{
namespace: 'alert',
os: ['h5'],
defaultParams: {
message: '',
},
runCode(message) {
alert('h5-' + message);
},
}]); quick.extendModule('ui', [{
namespace: 'alert',
os: ['quick'],
defaultParams: {
message: '',
},
runCode(message) {
alert('quick-' + message);
},
}]);

最终的调用如下(结果和预期一致)

quick.os.quick = true;
quick.ui.alert('hello'); // quick-hello
quick.os.quick = false;
quick.ui.alert('hello'); // h5-hello
quick.ui.alert = 11; // 提示:不允许修改quick API

虽然就一两个API来说,这类拓展方式看起来很复杂,但是当API一多,特别是还需批量预处理时(如默认参数,Promise支持等),它的优势就出来了

多平台支撑在quick中的应用

quick hybrid框架中,默认支持quickh5有种环境,核心代码就是上述列举的(当然,内部增加了一些代理,默认参数处理等,会稍微复杂一点)。

基于这个核心,然后可以将框架的定义和API定义分开打包

quick.js
quick.h5.js

这样,最终看起来h5下的API定义就是一个拓展包,是没有它也不会影响quick环境下的使用,而且,如果增加一个新的环境(比如dd),

只需要再新增另一个环境的拓展包而已,各种写法都是一样的,这样便于了统一维护

返回根目录

源码

github上这个框架的实现

quickhybrid/quickhybrid

【quickhybrid】API多平台支撑的实现的更多相关文章

  1. 关于HTML5音频——audio标签和Web Audio API各平台浏览器的支持情况

    对比audio标签 和 Web Audio API 各平台浏览器的支持情况:   audio element Web Audio API desktop browsers Chrome 14 Yes  ...

  2. flask + Python3 实现的的API自动化测试平台---- IAPTest接口测试平台(总结感悟篇)

    前言: 在前进中去发现自己的不足,在学习中去丰富自己的能力,在放弃时想想自己最初的目的,在困难面前想想怎么踏过去.在不断成长中去磨炼自己. 正文: 时间轴 flask + Python3 实现的的AP ...

  3. API管理平台XXL-API

    <API管理平台XXL-API> 一.简介 1.1 概述 XXL-API是一个简洁易用API管理平台,提供API的"管理"."文档"."M ...

  4. 高效、易用、功能强大的 api 管理平台

    前言导读 实际环境的需求可以说是:只有你没想到,没有实现不了的,征对于目前实际开发.测试.生产等环境中,需要用到各类的接口可达几十.甚至上百个,因此,必须需要一个统一管理的工具平台来统一管理这类接口, ...

  5. API 开发平台 dreamfactory,参考SAWAGGER,国外厂家,开源,本地与云部署

    API 开发平台,参考SAWAGGER,国外厂家,本地与云部署:参考  http://swagger.io/commercial-tools/ 1.dreamfactory 梦工厂公司  https: ...

  6. 国内最受欢迎的7大API供应平台对比和介绍

    俗话说“巧妇难为无米之炊”,数据源就是数据产生价值中的那些大米.那大数据时代企业需要哪些数据呢?根据我个人理解我觉得可以大致分为以下几类: 1.(内部)企业自身业务生产经营环节产生的内部数据[包括销售 ...

  7. Cucumber+Rest Assured快速搭建api自动化测试平台

    转载:http://www.jianshu.com/p/6249f9a9e9c4 什么是Cucumber?什么是BDD?这里不细讲,不懂的直接查看官方:https://cucumber.io/ 什么是 ...

  8. 选择API管理平台之前要考虑的5个因素

    API(应用程序编程接口)经济的飞速增长导致对API管理平台的需求相应增加. 这些解决方案可在整个生命周期内帮助创建,实施,监控,分析,保护和管理API. 据一些估计,全球API管理市场预计在2018 ...

  9. API开放平台接口设计-------基于OAuth2.0协议方式

    1,简介OAuth http://www.ruanyifeng.com/blog/2019/04/oauth_design.html OAuth 是什么? http://www.ruanyifeng. ...

随机推荐

  1. vue-cli 前端开发,后台接口跨域代理调试问题

    使用 webpack的方式开发的时候,前台开发过程中需要调用很多后台的数据接口,但是通常前后台分离的开发方式,后台的接口数据很可能是不方便或者是不能在前端同学的电脑上运行的,也就出现了所谓的跨域问题. ...

  2. 05).30分钟学会Servlet+过滤器+监听器+实际案例

    一.Servlet简介: Servlet程序处理流程 二.Servlet程序实现 实现要求 Servlet属于java ee范畴,而java和javac属于java se范畴,要想编译servlet必 ...

  3. 从零开始搭建Vue组件库 VV-UI

    前言: 前端组件化是当今热议的话题之一,也是我们在开发单页应用经常会碰到的一个问题,现在我们有了功能非常完善的Element-UI.各个大厂也相继宣布开源XXX-UI.但是也会存在一些问题,比如每个公 ...

  4. spirngMVC的搭建

    1 springMVC的搭建肯定是需要用到一系列的jar包的,那么第一步就是去spring官网下载对应版本的jar包 可以通过 http://www.cnblogs.com/imentors/p/49 ...

  5. DIY 温控烙铁

    由于工艺原因,某处要使用200W大功率烙铁(恒温烙铁虽然有那么大功率,但没有那么大的烙铁头),只能选用普通电热丝烙铁(无温控),存在温度过高现象(造成工艺不良,同时因助焊剂+高温造成烙铁头腐蚀),逐渐 ...

  6. phpcms v9 sql注入脚本

    phpcms v9 SQL注入脚本 用法:python phpcms.py http://www.baidu.com import requests,sys,urllib url = sys.argv ...

  7. 大雄和哆啦A梦

    题目:大雄和哆啦A梦题目介绍:这个图片名称有点奇怪?! 1,打开链接会看到大雄和哆啦A梦的照片,把它下载下来.就是下面这个图片. 2,用wireshark打开,会看到最后面出现 rar ,还有flag ...

  8. 如何有效的去使用一款免费的ERP

    现在市场上免费的软件不少,怎么样去使用一款免费产品是很多人比较头疼的事情. 一般使用免费ERP软件的基本都是小企业,没用过想用又舍不得花钱.如果企业有懂数据库这块儿的管理员,那都还好.如果没有,那建议 ...

  9. kvm虚拟机管理 系统自动化安装

    原创博文安装配置KVM http://www.cnblogs.com/elvi/p/7718574.htmlweb管理kvm http://www.cnblogs.com/elvi/p/7718582 ...

  10. poj 3431 Expedition 优先队列

    poj 3431 Expedition 优先队列 题目链接: http://poj.org/problem?id=2431 思路: 优先队列.对于一段能够达到的距离,优先选择其中能够加油最多的站点,这 ...