全新上架!商用级别的 Excel 解析工具

解决了大部分开发者的痛点的 Excel 解析工具
商店地址: Excel to JSON | Cocos Store

工具简介

工具用于将 Excel 转为 json,并提供所有的代码提示。

.
├── Creator351 # 示例工程
├── bin # 此解析插件的 js 脚本
├── xlsx # 此插件的示例 Excel 文件集合
├── export # 插件导出的内容
    ├── json # 插件导出的 json 文件
    └── script # 插件导出的脚本
├── node_modules # npm install 后的依赖项
├── package-lock.json # npm install 后的 lock 文件
├── package.json # npm 项目的 package.json 
└── README.md # 说明文档

Excel 相关配置规则

具体包括以下内容:

  1. 解析将跳过以下格式的 xlsx 文件:

    • 跳过扩展名不是 .xlsx 的文件;
    • 跳过 ~ 开头的文件;
    • 跳过 .~ 开头的文件(windows 下打开 Excel 产生的临时文件);
  2. 一个 Xlsx 文件支持多个 Sheet 的解析机制;Sheet 是否解析由其名字决定:

    • 以 “~” 开头的 Sheet 不解析;
    • Sheet 名称必须以 “@” 符号作为分隔符;
    • @ 后面必须是纯字母或数字;
    • @ 前面一般用于标记配置表的中文名称;
  3. 列解析原则:

    • 只解析 “c”、“s”、“cs”、“sc” 开头的列,其余列忽略;(一般建议忽略的列,以 “//” 开头);
    • 第一列的字段名必须为小写的 “id”;
  4. 行解析原则:id 段值为空或者以 // 开头的行都将忽略该行数据的解析;

  5. Excel 表支持的字段类型(具体参见 xlsx 中的示例配置表):
    number、string、int、
    number[]、int[]、string[]、
    number[][]、int[][]、string[][]、
    {xx: number, yy:string}、
    u|id:int#cnt:int#price:number、
    u|id:int#cnt:int#price:number[]、
    u|id:int#cnt:int#price:number[][]

  6. 导出的 json 数据精简机制;json 数据进行了字段的压缩,降低了 json 数据的大小(具体可查看 export 文件夹中的数据,进行了解);

  7. 多语言表解析机制(可参考 xlsx 中关于多语言表的配置);

  8. 全局表解析机制(可参考 xlsx 中关于全局表的配置);

  9. 自动生成代码机制;(属性声明文件、配置表访问类、配置表管理器)字段名强类型提示功能(具体参考 Creator351 工程中的示例);

  10. 自动生成 id 枚举类并支持注释的机制(参考 IKey.ts 中的示例);

  11. 游戏使用示例工程(Creator 3.5.1)

初始化工具

在当前目录下执行以下命令,在相关依赖安装完毕后,就可以使用 Excel 解析工具了

npm install

插件如何使用

  1. 生成 json 和 script 到 export 目录
# 使用 package 定义的指令
npm run demo

# 实际调用的是以下指令(二者等价)
node ./bin/main.js -d -s ./xlsx -o ./export/json/ --out-script-path ./export/script/
  1. 生成 json 和 script 到 ./Creator351/assets/xlsx 目录
# 使用 package 定义的指令
npm run cocos

# 实际调用的是以下指令(二者等价)
node ./bin/main.js -d -s ./xlsx -o ./Creator351/assets/xlsx/json/ --out-script-path ./Creator351/assets/xlsx/script/

以下是一次解析控制台示例

➜  store git:(master) npm run demo

> excel_to_any@1.0.0 demo
> node ./bin/main.js -d -s ./xlsx -o ./export/json/ --out-script-path ./export/script/

{
  debug: true,
  srcPath: './xlsx',
  outJsonsPath: './export/json/',
  outScriptPath: './export/script/'
}
>> xlsx 所在目录路径 : /Users/z/Desktop/excel_to_any/store/xlsx
>> 输出 json 路径 : /Users/z/Desktop/excel_to_any/store/export/json
>> 输出 script 路径 : /Users/z/Desktop/excel_to_any/store/export/script
>> 开始解析 xlsx 文件: /Users/z/Desktop/excel_to_any/store/xlsx/示例表.xlsx
    开始解析: 示例表@demo
      >> 跳过 (~ 开头) : ~测试表@demo2
>> 开始解析 xlsx 文件: /Users/z/Desktop/excel_to_any/store/xlsx/多语言表.xlsx
    开始解析: 多语言表@Lang
>> 开始解析 xlsx 文件: /Users/z/Desktop/excel_to_any/store/xlsx/全局配置表.xlsx
    开始解析: 全局表@g
生成多语言文件: Lang-zh-cn.json
生成多语言文件: Lang-en.json
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 解析完成!!!

游戏中如何使用

参考 Creator351 工程的使用示例即可。

主要包含几个内容:

  1. xlsx 实例对象。用于将加载后的 json 数据进行注册;各个 Sheet 表访问的入口;全局表访问的入口;
  2. lang 实例对象。用于多语言的配置表数据添加、多语言的切换;多语言文本的访问;自动替换多语言中的变量的机制;
import { assetManager, AssetManager, Component, JsonAsset, _decorator } from 'cc';
import { id_Lang } from './xlsx/script/IKey';
import { lang } from './xlsx/script/lang';
import { xlsx } from './xlsx/script/xlsx';
const { ccclass, property } = _decorator;

/**
 * xlsx 工具导出的 json 文件清单格式
 */
type IManifestJson = {
    data: {
        key: string,
        name: string,
    }[]
}

/**
 * 这是游戏的入口脚本,挂载在 EntryScene 的 Canvas 中 
 */
@ccclass('EntryScene')
export class EntryScene extends Component {
    async start() {
        /** 
         * assets/xlsx 被标记为一个 bundle 包,xlsx 是其包名;
         * 因此要先加载该 Bundle 包
         */
        const xlsxBundle = await new Promise(resolve => {
            assetManager.loadBundle("xlsx", (err, bundle: AssetManager.Bundle) => {
                if (err) {
                    console.log(`excel_to_any >> 加载 bundle 包 xlsx >> 失败`, err);
                    resolve(null);
                    return;
                }
                console.log(`excel_to_any >> 加载 bundle 包 xlsx >> 成功`);
                resolve(bundle);
            });
        });

        /** 如果加载 xlsx 包失败,直接返回 */
        if (!xlsxBundle) {
            return;
        }

        /**
         * 加载 xlsx 导出的 json 文件清单。 注意:
         *     1、json/_manifest 是相对于包 xlsx 的文件路径(加载 json 文件不需要指定其扩展名 .json)
         *     2、IManifestJson 是清单中的数据格式
         */
        const _manifest = await this.LoadJsonAsync<IManifestJson>("json/_manifest", "xlsx");

        /** 根据清单,加载所有配置表(除了多语言) */
        for (let i = _manifest.data.length - 1; i >= 0; --i) {
            /** 加载配置文件 */
            const jsonData = await this.LoadJsonAsync(`json/${_manifest.data[i].key}`, "xlsx");
            console.log(`加载 ${_manifest.data[i].name} 表成功`);
            xlsx.AddXlsx(_manifest.data[i], jsonData);
        }

        console.log(` ----------------- 普通表测试 ----------------- `)
        console.log(`demo >> `, xlsx.demo.row(100))
        console.log(`demo >> id: `, xlsx.demo.row(100).id)
        console.log(`demo >> name: `, xlsx.demo.row(100).name)
        console.log(`demo >> strList: `, xlsx.demo.row(100).strList)
        console.log(`demo >> strList2: `, xlsx.demo.row(100).strList2)
        console.log(`demo >> intTyp: `, xlsx.demo.row(100).intTyp)
        console.log(`demo >> intList: `, xlsx.demo.row(100).intList)
        console.log(`demo >> intList2: `, xlsx.demo.row(100).intList2)
        console.log(`demo >> numTyp: `, xlsx.demo.row(100).numTyp)
        console.log(`demo >> numList: `, xlsx.demo.row(100).numList)
        console.log(`demo >> numList2: `, xlsx.demo.row(100).numList2)
        console.log(`demo >> id_cnt_price: `, xlsx.demo.row(100).id_cnt_price)
        console.log(`demo >> id_cnt_price_arr: `, xlsx.demo.row(100).id_cnt_price_arr)
        console.log(`demo >> id_cnt_price_arr2: `, xlsx.demo.row(100).id_cnt_price_arr2)

        console.log(` ----------------- 全局表测试 ----------------- `)
        console.log(`g >> intArr2Val: `, xlsx.g.intArr2Val);
        console.log(`g >> intArrVal: `, xlsx.g.intArrVal);
        console.log(`g >> intVal: `, xlsx.g.intVal);
        console.log(`g >> json1: `, xlsx.g.json1);
        console.log(`g >> userVal: `, xlsx.g.userVal);
        console.log(`g >> userArrVal: `, xlsx.g.userArrVal);
        console.log(`g >> userArr2Val: `, xlsx.g.userArr2Val);


        console.log(` ----------------- 多语言表测试 ----------------- `)
        /** 语言包单独加载 */
        const _lang_zh_cn_Json = await this.LoadJsonAsync<IManifestJson>("json/Lang-zh-cn", "xlsx");
        /** 添加语言包 */
        lang.AddLang("zh-cn", _lang_zh_cn_Json);
        /** 设置当前语音包 */
        lang.SetLang("zh-cn");
        /** 打印中文 */
        console.log(lang.text(id_Lang.com_confirm));
        console.log(lang.text(id_Lang.cost_n, { n: 99 }));
        
        
        const _lang_en_Json = await this.LoadJsonAsync<IManifestJson>("json/Lang-en", "xlsx");
        /** 添加语言包 */
        lang.AddLang("en", _lang_en_Json);
        lang.SetLang("en");
        /** 打印英文 */
        console.log(lang.text(id_Lang.com_confirm));
        console.log(lang.text(id_Lang.cost_n, { n: 88 }));
    }


    /**
     * 定义如何加载 json 文件的方法(一般框架级别会有自己的资源管理解决方案,可自行替换)
     * @param jsonPath json 文件所在 bundle 中的路径
     * @param bundleKey bundle 名称
     * @returns 
     */
    private LoadJsonAsync<JSON_DATA>(jsonPath: string, bundleKey: string): Promise<JSON_DATA> {
        return new Promise(resolve => {
            const bundle = assetManager.getBundle(bundleKey);
            bundle.load(jsonPath, JsonAsset, (err, asset) => {
                if (err) {
                    console.error(err);
                    resolve(null);
                    return;
                }
                resolve(asset.json as any as JSON_DATA);
            });
        });
    }
}
1赞