菜单

澳门金沙手机投注网仙剑奇侠传的web移植版

2019年3月26日 - 金沙前端

1. 无图言屌

优酷摄像——有录制有JB!

澳门金沙手机投注网 1澳门金沙手机投注网 2

澳门金沙手机投注网 3

澳门金沙手机投注网 4

澳门金沙手机投注网 5

澳门金沙手机投注网 6

澳门金沙手机投注网 7

澳门金沙手机投注网 8

澳门金沙手机投注网 9

前言

API完成阶段之JS端的完成,重点描述这么些项指标JS端都某些什么内容,是怎么着贯彻的。

不一样于一般混合框架的只含有JSBridge部分的前端完成,本框架的前端完成包蕴JSBridge部分、多平台支撑,统一预处理等等。

类型的结构

在初期的版本中,其实全数前端库就只有一个文书,里面只分明着什么样达成JSBridge和原生交互部分。可是到新型的版本中,由于效果日渐增多,单一文件难以满意供给和保证,由此重构成了一整个项目。

整体项目基于ES6Airbnb代码规范,使用gulp + rollup塑造,部分根本代码进行了Karma + Mocha单元测试

完全目录结构如下:

quickhybrid
    |- dist             // 发布目录
    |   |- quick.js
    |   |- quick.h5.js
    |- build            // 构建项目的相关代码
    |   |- gulpfile.js
    |   |- rollupbuild.js
    |- src              // 核心源码
    |   |- api          // 各个环境下的api实现 
    |   |   |- h5       // h5下的api
    |   |   |- native   // quick下的api
    |   |- core         // 核心控制
    |   |   |- ...      // 将核心代码切割为多个文件
    |   |- inner        // 内部用到的代码
    |   |- util         // 用到的工具类
    |- test             // 单元测试相关
    |   |- unit         
    |   |   |- karma.xxx.config.js
    |   |- xxx.spec.js
    |   |- ...

澳门金沙手机投注网 10

声音

澳门金沙网投平台,澳门金沙手机投注网,2.5. 为啥没兑现音乐/音响效果部分,不是有奥迪(Audi)o和Web奥迪(Audi)o了吗?

音响效果部分仙剑用的是voc格式,那么些格式太古老了以至于奥迪(Audi)o和Web奥迪o都不恐怕一向辅助它。为了不对财富文件做预处理的原则,在此地就让它坑了。

音乐部分仙剑用的是MIDI,方今在Web里有MIDI.js能够拍卖(P.S.那些类型十三分之屌!)。然则懂MIDI的人都清楚,MIDI格式本人并不复杂,难的在于完结音色库。那样一来会引入相当的大学一年级堆东西,甚至上百MB的音色库,那充裕不具体,所以作者选取先(forever)把它坑了。

UA约定

错落开发容器中,须要有三个UA标识位来判断当前系统。

此地Android和iOS原生容器统一在webview中增加如下UA标识(也便是说,假设容器UA中有其一标识位,就象征是quick环境-那也是os判断的贯彻原理)

String ua = webview.getSettings().getUserAgentString();

ua += " QuickHybridJs/" + getVersion();

// 设置浏览器UA,JS端通过UA判断是否属于quick环境
webview.getSettings().setUserAgentString(ua);

// 获取默认UA
NSString *defaultUA = [[UIWebView new] stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];

NSString *version = [[NSBundle mainBundle].infoDictionary objectForKey:@"CFBundleShortVersionString"];

NSString *customerUA = [defaultUA stringByAppendingString:[NSString stringWithFormat:@" QuickHybridJs/%@", version]];

[[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent":customerUA}];

如上述代码中分头在Android和iOS容器的UA中添加重心的标识位。

合并的预处理

在上一篇API多平台的支撑中有提到怎么样依据Object.defineProperty贯彻几个援救多平台调用的API,实现起来的API大约是那样子的

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');
    },
});

...

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

其中nameSpaceApi.h5的值是api.runCode,也正是说直接实施runCode(...)中的代码

单纯那样是不够的,我们供给对调用方法的输入等做联合预处理,因而在此地,我们依据实际的动静,在此基础上更是周详,加上统一预处理机制,也就是

const newProxy = new Proxy(api, apiRuncode);

Object.defineProperty(apiParent, apiName, {
    ...
    get: function proxyGetter() {
        ...
        return newProxy.walk();
    }
});

咱俩将新的运行代码变为三个代理对象Proxy,代理api.runCode,然后在get时回来代理过后的实际上方法(.walk()方法表示代理对象内部会开始展览三回联合的预处理)

代理对象的代码如下

function Proxy(api, callback) {
    this.api = api;
    this.callback = callback;
}

Proxy.prototype.walk = function walk() {
    // 实时获取promise
    const Promise = hybridJs.getPromise();

    // 返回一个闭包函数
    return (...rest) = >{
        let args = rest;

        args[0] = args[0] || {};
        // 默认参数的处理
        if (this.api.defaultParams && (args[0] instanceof Object)) {
            Object.keys(this.api.defaultParams).forEach((item) = >{
                if (args[0][item] === undefined) {
                    args[0][item] = this.api.defaultParams[item];
                }
            });
        }

        // 决定是否使用Promise
        let finallyCallback;

        if (this.callback) {
            // 将this指针修正为proxy内部,方便直接使用一些api关键参数
            finallyCallback = this.callback;
        }

        if (Promise) {
            return finallyCallback && new Promise((resolve, reject) = >{
                // 拓展 args
                args = args.concat([resolve, reject]);
                finallyCallback.apply(this, args);
            });
        }

        return finallyCallback && finallyCallback.apply(this, args);
    };
};

从源码中得以看来,那几个代理对象统一预处理了两件工作:

再者,后续要是有新的联合预处理(调用API前的预处理),只需在那些代理对象的这一个方法中增添即可

动画

Name Latest Release License Notes
sprite.js   VIEW Created with goal of having common JS framework for dsktop and web. 1

0. 前言

那是三个坑了太久太久的体系,久到自家早已不记得挖这一个坑是如何时候了。大约是13年的夏日呢,我挖了那一个坑,然后信心满满的在当年十一长假宅了N天(笔者还相比清楚的回忆那时候便是WOW开开垦荒地地围攻奥格瑞玛副本的阶段),写下了全方位框架,以及最中央的一局地代码,然后,就不曾然后了。

大概一年后,小编又翻出来了那么些坑,重构了汪洋的代码,可是速度大致从不实质性的前行,甚至因为重构而有所倒退-
-“,可是因为读了《游戏引擎架构》那本书,小编对这几个坑又有了新的认识,对于那个顺序到底要怎么写心里有谱多了。

自然安插是在当年夏天搞出来,那样能够境遇仙剑20周年(1993年十1月)发表,可是并非想也领略肯定是两次三番坑了。

磕磕绊绊到近期,总算是把嬉戏的总体完毕度拉到了多个相比能见人的程度,于是自个儿觉得照旧赶紧发布的好,免得又变有生之年了。

统一的预处理

在上一篇API多平台的支撑中有提到如何依据Object.defineProperty兑现一个扶助多平台调用的API,完毕起来的API大概是那样子的

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');
    },
});

...

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

其中nameSpaceApi.h5的值是api.runCode,也便是说直接执行runCode(...)中的代码

单独那样是不够的,大家须要对调用方法的输入等做统一预处理,由此在那边,我们依据实际的气象,在此基础上更是周详,加上统一预处理机制,也就是

const newProxy = new Proxy(api, apiRuncode);

Object.defineProperty(apiParent, apiName, {
    ...
    get: function proxyGetter() {
        ...
        return newProxy.walk();
    }
});

大家将新的运维代码变为一个代理对象Proxy,代理api.runCode,然后在get时回来代理过后的骨子里方法(.walk()方法表示代理对象内部会开始展览一遍联合的预处理)

代理对象的代码如下

function Proxy(api, callback) {
    this.api = api;
    this.callback = callback;
}

Proxy.prototype.walk = function walk() {
    // 实时获取promise
    const Promise = hybridJs.getPromise();

    // 返回一个闭包函数
    return (...rest) = >{
        let args = rest;

        args[0] = args[0] || {};
        // 默认参数的处理
        if (this.api.defaultParams && (args[0] instanceof Object)) {
            Object.keys(this.api.defaultParams).forEach((item) = >{
                if (args[0][item] === undefined) {
                    args[0][item] = this.api.defaultParams[item];
                }
            });
        }

        // 决定是否使用Promise
        let finallyCallback;

        if (this.callback) {
            // 将this指针修正为proxy内部,方便直接使用一些api关键参数
            finallyCallback = this.callback;
        }

        if (Promise) {
            return finallyCallback && new Promise((resolve, reject) = >{
                // 拓展 args
                args = args.concat([resolve, reject]);
                finallyCallback.apply(this, args);
            });
        }

        return finallyCallback && finallyCallback.apply(this, args);
    };
};

从源码中得以看来,这一个代理对象统一预处理了两件业务:

并且,后续假诺有新的联结预处理(调用API前的预处理),只需在这一个代理对象的这么些措施中追加即可

关于代码规范与单元测试

花色中应用的Airbnb代码规范并不是100%顺应原版,而是依照项目标事态定制了下,不过完全上95%如上是顺应的

再有一块正是单元测试,那是很简单忽视的一块,可是也挺难做好的。那个体系中,基于Karma + Mocha开始展览单元测试,而且并不是测试驱动,而是在分明好剧情后,对基本部分的代码都开展单测。
里面对此API的调用基本都是靠JS来模拟,对于一些奇异的法门,还需Object.defineProperty(window.navigator, name, prop)来改变window自己的性质来模拟。
本项目中的主旨代码已经完毕了100%的代码覆盖率。

切实的代码那里不赘述,能够参照源码

Color

2. 自问自答的FAQ

代码架构

体系代少将主旨代码和API达成代码分开,大旨代码也正是1个处理引擎,而各样环境下的不等API达成能够独自挂载(那里是为了便于其余地点结合分歧条件下的API所以才分开的,实际上能够将native和焦点代码打包到共同)

quick.js
quick.h5.js
quick.native.js

那里须要注意,quick.xx环境.js中的代码是基于quick.js主干代码的(譬如里面须要接纳一些本性的敏捷调用底层的法门)

而里面最基本的quick.js代码架构如下

index
    |- os               // 系统判断相关
    |- promise          // promise支持,这里并没有重新定义,而是判断环境中是否已经支持来决定是否支持
    |- error            // 统一错误处理
    |- proxy            // API的代理对象,内部对进行统一预处理,如默认参数,promise支持等
    |- jsbridge         // 与native环境下原生交互的桥梁
    |- callinner        // API的默认实现,如果是标准的API,可以不传入runcode,内部默认采用这个实现
    |- defineapi        // API的定义,API多平台支撑的关键,也约定着该如何拓展
    |- callnative       // 定义一个调用通用native环境API的方法,拓展组件API(自定义)时需要这个方法调用
    |- init             // 里面定义config,ready,error的使用
    |- innerUtil        // 给核心文件绑定一些内部工具类,供不同API实现中使用

能够看来,主题代码已经被切割成非常的小的单元了,纵然说最终包装起来一共代码也平昔不稍微,不过为了维护性,简洁性,那种拆分仍然很有须要的

代码架构

品类代少校宗旨代码和API达成代码分开,主旨代码相当于贰个拍卖引擎,而相继环境下的不相同API完结能够单独挂载(那里是为了方便其余地点结合不一致条件下的API所以才分开的,实际上可以将native和基本代码打包到一块儿)

quick.js
quick.h5.js
quick.native.js

这边须求小心,quick.xx环境.js中的代码是依据quick.js骨干代码的(譬如里面须求选择一些特性的迅猛调用底层的办法)

而里面最基本的quick.js代码框架结构如下

index
    |- os               // 系统判断相关
    |- promise          // promise支持,这里并没有重新定义,而是判断环境中是否已经支持来决定是否支持
    |- error            // 统一错误处理
    |- proxy            // API的代理对象,内部对进行统一预处理,如默认参数,promise支持等
    |- jsbridge         // 与native环境下原生交互的桥梁
    |- callinner        // API的默认实现,如果是标准的API,可以不传入runcode,内部默认采用这个实现
    |- defineapi        // API的定义,API多平台支撑的关键,也约定着该如何拓展
    |- callnative       // 定义一个调用通用native环境API的方法,拓展组件API(自定义)时需要这个方法调用
    |- init             // 里面定义config,ready,error的使用
    |- innerUtil        // 给核心文件绑定一些内部工具类,供不同API实现中使用

能够见见,核心代码已经被切割成非常的小的单元了,纵然说最后包装起来一共代码也没有稍微,不过为了维护性,简洁性,这种拆分照旧很有必不可少的

Math

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图