CocosCreator JavaScript/TypeScript混编
为什么要混编
首先,如果一个新的项目,能ts就ts了。其实也用不着混编了。但是搁不住有本身是js的项目。在或者起初对ts不了解。首先用了js,后来想改,但是项目规模上来了。全篇修改太困难。现在想用ts的类型提示的便利,有懒得去修改之前的老旧代码。那么知道一些混编的技巧就很重要了。
全局变量/函数
之前直接定义在window里面的变量和方法,在ts里面直接用是没问题的。但是VSCode会给出红线提示。十分碍眼。直接写window.Xxx,会显示没有这个变量的红线。因此应用globalThis.代替window.:
globalThis.NotificationCenter.pushNotification('as_fadeOut');
还可以在所需要文件开头就把需要用到的原window.下面的内容定义在文件范围内的同名变量下:
let NotificationCenter = globalThis.NotificationCenter;
总之globalThis就是TS里面声明类型为any的window.
如果是针对微信小游戏,在发布到微信开发者工具后,微信开发者工具对globalThis无法识别会导致错误,而且报出其它的莫名其妙的错误。需要针对微信小游戏平台进行一个简单的适配:
if (window.wx != null) { window.globalThis = window; }
放在一开始就好了,其它调用的地方该怎么写还是怎么写不变。
TS中类型引用到全局,以及对象的单例模式
但是TS类放到全局的时候我依然习惯了window,引用对象的获取也习惯使用单例:
这里BaseView是继承自cc.Component的。
如果是个prefab,很明显,在这个node被指定parent的时候,单例对象开始存在了。
@ccclass
export default class GameData extends BaseView {
private static _instance: GameData = null;
public static getInstance(): GameData {
return this._instance;
}
constructor() {
super();
GameData._instance = this;
}
// ...
}
(<any>window).GameData = GameData;
这样使用单例:(不论ts还是js都一样)
GameData.getInstance().totalTrophy.value = _.trophy;
JS引用TS的default导出
const { ccclass, property } = cc._decorator;
@ccclass
export default class BaseSwitchPanelEx extends cc.Component {
// ...
}
js应用ts,不考虑路径
let BaseSwitchPanelEx = require('BaseSwitchPanelEx').default;
JS引用TS的非default导出
export {
// ...
CCBindButton, CCBindAnimation, CCBindAnimationSimple,
// ...
};
js引用ts,不考虑路径
let CCBindButton = require('RxTools').CCBindButton;
或者可以这样写,以便于直接引用到其中的多个(这似乎叫做析构语法):
let { CCBindButton, CCBindAnimation } = require('RxTools');
JS引用TS,通过import语法
这部分我不是很了解
需要利用npm,先安装了@types。然后js代码里面就可以如同ts代码里面写如:
import Dialog from './Dialog';
其中Dialog是个同级目录下的ts文件。这里是用default导出的。
TS引用JS
直接require即可,就如同JS一样,同样不需要考虑路径
const i18n = require('LanguageData');
TS利用类型的引用结构分拆代码
这部分跟混编无关,暂时不知道JS里面如何去写
为了引用图集资源SpriteFrame:
const { ccclass, property } = cc._decorator;
@ccclass('SpriteFramesManagerResource')
export default class SpriteFramesManagerResource {
@property(cc.SpriteFrame)
coin: cc.SpriteFrame = null;
@property(cc.SpriteFrame)
diamond: cc.SpriteFrame = null;
@property(cc.SpriteFrame)
powerCoin: cc.SpriteFrame = null;
}
如果这个类继承cc.Component,那么直接在编辑器中指定引用即可。但是我有很多引用,希望归类。就写一个总的cc.Component,引用到这些子类。
import { BaseView } from "../../Rx/BaseView";
import SpriteFramesManagerResource from "./SpriteFramesManagerResource";
// ... 其它的分类导入
const { ccclass, property } = cc._decorator;
@ccclass
export default class BasicAssetsRefManager extends BaseView {
private static _instance: BasicAssetsRefManager = null;
public static getInstance(): BasicAssetsRefManager {
return this._instance;
}
constructor() {
super();
BasicAssetsRefManager._instance = this;
}
@property(SpriteFramesManagerResource)
resource: SpriteFramesManagerResource = new SpriteFramesManagerResource();
// ... 其它的分类
}
在编辑器上,也会自动分类折叠这些自类引用。
最后
- 对于一些暂时没办法的红线提示 就使用:
//@ts-ignore
来规避吧。 - 要意识到,原JS里面的东西,进TS里面都是any。需要的话,使用
<>
给出定义。 - import需要考虑路径,require都不用。
- 考虑路径的引用,如果需要移动位置。在vscode里面可以自动修改引用目录关联(但是要注意meta文件可能变化导致引用丢失)