在开发过程中,Excel数据表格是我们很常用的数据存储工具,但是我们如何在程序中更方便快捷的去使用Excel中的数据呢?
首先说明下json格式是我们在开发中经常使用到的一种数据存储结构。JSON,实际上就是一种规范的存储数据的结构,它具有结构简明、实现方便、多变万用、跨平台等特点,深受开发者们喜爱。
我们需要引入三个dll文件,Newtonsoft.Json.dll、Excel.dll、ICSharpCode.SharpZipLib、文章下面附有demo工程。
Excel数据结构定义
我们看一个简单的Excel数据结构
第一行是每个变量名的说明,大家也可以在这一行做标签处理,说明更具体些。
第二行第一列定义为类名与unity代码类名一一对应,这样方便在代码中查找相应类以及对其引用。
第二行其他列定义为类的变量名与代码中变量名一一对应,再导出json后,我们能快速通过这些变量名绑定到相应的类中。
代码逻辑
1.首先我们定义editor工具类,去导出Excel数据。
给定指定的Excel文件夹路径,整体导出json数据
2.讲解下ExcelUtility类
构造函数打开相应的Excel文件
导出json,一行一行的去读取Excel数据
///
/// 转换为Json
///
/// Json文件路径
/// 表头行数
public void ConvertToJson(string JsonPath, Encoding encoding, string name)
{
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return;
//默认读取第一个数据表
DataTable mSheet = mResultSet.Tables[0];
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
return;
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//准备一个列表存储整个表的数据
//Dictionary>> dic = new Dictionary>>();
List> table = new List>();
//string excelName = mSheet.Rows[1][0].ToString();
//dic[excelName] = table;
//读取数据
for (int i = 2; i < rowCount; i++)
{
//准备一个字典存储每一行的数据
Dictionary row = new Dictionary();
for (int j = 0; j < colCount; j++)
{
//读取第2行数据作为表头字段
string field = mSheet.Rows[1][j].ToString();
if (String.IsNullOrEmpty(field)) continue;
//Key-Value对应
row[field] = mSheet.Rows[i][j];
}
//添加到表数据中
table.Add(row);
}
//生成Json字符串
string json = JsonConvert.SerializeObject(table, Newtonsoft.Json.Formatting.Indented);
//json = StringEncryption.EncryptDES(json); //加密
//写入文件
//string newJsonPath = Application.streamingAssetsPath + "/" + GetAssetPath(excelName + ".json");
using (FileStream fileStream = new FileStream(JsonPath, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, encoding))
{
textWriter.Write(json);
}
}
}
导出lua代码结构如导出json类似,自己去拼接lua每一行代码。
///
/// 转换为lua
///
/// lua文件路径
public void ConvertToLua(string luaPath, Encoding encoding ,ref List fileNames)
{
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return;
//读取数据表
foreach (DataTable mSheet in mResultSet.Tables)
{
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
continue;
if (!mSheet.Rows[0][0].ToString().Equals("类名"))
continue;
string fileName = "test";
fileName = mSheet.Rows[1][0].ToString();
if (String.IsNullOrEmpty(fileName)) continue;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("local "+fileName+" = {");
stringBuilder.Append("\r\n");
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//准备一个列表存储整个表的数据
List> table = new List>();
//读取数据
for (int i = 2; i < rowCount; i++)
{
bool isNext = false;
for (int m = 0; m < colCount; m++)
{
string objStr = mSheet.Rows[i][m].ToString();
if (!string.IsNullOrEmpty(objStr) && objStr != "null")
{
isNext = true;
break;
}
}
if (!isNext) continue;
//准备一个字典存储每一行的数据
Dictionary row = new Dictionary();
for (int j = 1; j < colCount; j++)
{
//读取第1行数据作为表头字段
string field = mSheet.Rows[1][j].ToString();
//Key-Value对应
row[field] = mSheet.Rows[i][j];
}
//添加到表数据中
table.Add(row);
}
//stringBuilder.Append(string.Format("\t\"{0}\" = ", mSheet.TableName));
//stringBuilder.Append("{\r\n");
foreach (Dictionary dic in table)
{
stringBuilder.Append("\t\t{\r\n");
foreach (string key in dic.Keys)
{
if (string.IsNullOrEmpty(key)) continue;
object valueObj = dic[key];
Type type = valueObj.GetType();
if (valueObj.GetType().Name == "String")
{
string valueStr = valueObj as string;
string str = valueStr.Replace("\"", "\\\"");
if (!string.IsNullOrEmpty(valueStr))
stringBuilder.Append(string.Format("\t\t\t{0} = \"{1}\",\r\n", key, str));
else
stringBuilder.Append(string.Format("\t\t\t{0} = nil,\r\n", key));
}
else if (valueObj == null || valueObj.GetType().Name == "DBNull")
stringBuilder.Append(string.Format("\t\t\t{0} = nil,\r\n", key));
else
stringBuilder.Append(string.Format("\t\t\t{0} = {1},\r\n", key, valueObj));
}
stringBuilder.Append("\t\t},\r\n");
}
stringBuilder.Append("}\r\n");
stringBuilder.Append("_G."+fileName+" = "+ fileName);
stringBuilder.Append("\r\n");
stringBuilder.Append("setmetatable(_G," + fileName + ")");
stringBuilder.Append("\r\n");
stringBuilder.Append("return " + fileName);
fileNames.Add(fileName);
fileName += ".lua";
string writePath = Path.Combine(luaPath, fileName);
//写入文件
using (FileStream fileStream = new FileStream(writePath, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, encoding))
{
textWriter.Write(stringBuilder.ToString());
}
}
}
}
ExcelUtility完整代码
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Excel;
using System.Data;
using System.IO;
using Newtonsoft.Json;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System;
public class ExcelUtility
{
///
/// 表格数据集合
///
private DataSet mResultSet;
///
/// 构造函数
///
/// Excel file.
public ExcelUtility(string excelFile)
{
if (File.Exists(excelFile))
{
FileStream mStream = File.Open(excelFile, FileMode.Open, FileAccess.Read);
IExcelDataReader mExcelReader = ExcelReaderFactory.CreateOpenXmlReader(mStream);
mResultSet = mExcelReader.AsDataSet();
}
}
///
/// 转换为实体类列表
///
public List ConvertToList()
{
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return null;
//默认读取第一个数据表
DataTable mSheet = mResultSet.Tables[0];
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
return null;
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//准备一个列表以保存全部数据
List list = new List();
//读取数据
for (int i = 1; i < rowCount; i++)
{
//创建实例
Type t = typeof(T);
ConstructorInfo ct = t.GetConstructor(System.Type.EmptyTypes);
T target = (T)ct.Invoke(null);
for (int j = 0; j < colCount; j++)
{
//读取第1行数据作为表头字段
string field = mSheet.Rows[0][j].ToString();
object value = mSheet.Rows[i][j];
//设置属性值
SetTargetProperty(target, field, value);
}
//添加至列表
list.Add(target);
}
return list;
}
public string GetAssetPath(string name)
{
string Platform = "";
#if UNITY_IOS
Platform="iOS";
#elif UNITY_ANDROID
Platform = "Android";
#elif UNITY_WEBPLAYER
Platform ="WebPlayer";
#elif UNITY_WP8
Platform="WP8Player";
#elif UNITY_METRO
Platform = "MetroPlayer";
#elif UNITY_OSX || UNITY_STANDALONE_OSX
Platform = "StandaloneOSXIntel";
#else
Platform = "StandaloneWindows";
#endif
string path = Path.Combine(Platform, name); //System.String.Format("{0}/{1}", Platform, name);
//string path = Platform + "/" + name;
return path;
}
///
/// 转换为Json
///
/// Json文件路径
/// 表头行数
public void ConvertToJson(string JsonPath, Encoding encoding, string name)
{
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return;
//默认读取第一个数据表
DataTable mSheet = mResultSet.Tables[0];
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
return;
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//准备一个列表存储整个表的数据
//Dictionary>> dic = new Dictionary>>();
List> table = new List>();
//string excelName = mSheet.Rows[1][0].ToString();
//dic[excelName] = table;
//读取数据
for (int i = 2; i < rowCount; i++)
{
//准备一个字典存储每一行的数据
Dictionary row = new Dictionary();
for (int j = 0; j < colCount; j++)
{
//读取第2行数据作为表头字段
string field = mSheet.Rows[1][j].ToString();
if (String.IsNullOrEmpty(field)) continue;
//Key-Value对应
row[field] = mSheet.Rows[i][j];
}
//添加到表数据中
table.Add(row);
}
//生成Json字符串
string json = JsonConvert.SerializeObject(table, Newtonsoft.Json.Formatting.Indented);
//json = StringEncryption.EncryptDES(json); //加密
//写入文件
//string newJsonPath = Application.streamingAssetsPath + "/" + GetAssetPath(excelName + ".json");
using (FileStream fileStream = new FileStream(JsonPath, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, encoding))
{
textWriter.Write(json);
}
}
}
public void ConvertToJson(string AssetPath, Encoding encoding)
{
string fileName = "test";
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return;
for(int ln = 0; ln < mResultSet.Tables.Count;ln++ )
{
//默认读取第一个数据表
DataTable mSheet = mResultSet.Tables[ln];
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
continue;
if (!mSheet.Rows[0][0].ToString().Equals("类名"))
continue;
fileName = mSheet.Rows[1][0].ToString();
if (String.IsNullOrEmpty(fileName)) continue;
fileName += ".json";
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//准备一个列表存储整个表的数据
//Dictionary>> dic = new Dictionary>>();
List> table = new List>();
//string excelName = mSheet.Rows[1][0].ToString();
//dic[excelName] = table;
//读取数据
for (int i = 2; i < rowCount; i++)
{
bool isNext = false;
for (int m = 0; m < colCount; m++)
{
string objStr = mSheet.Rows[i][m].ToString();
if (!string.IsNullOrEmpty(objStr) && objStr != "null")
{
isNext = true;
break;
}
}
if (!isNext) continue;
//准备一个字典存储每一行的数据
Dictionary row = new Dictionary();
for (int j = 1; j < colCount; j++)
{
//读取第2行数据作为表头字段
string field = mSheet.Rows[1][j].ToString();
if (String.IsNullOrEmpty(field)) continue;
//Key-Value对应
row[field] = mSheet.Rows[i][j];
}
//添加到表数据中
table.Add(row);
}
//生成Json字符串
string json = JsonConvert.SerializeObject(table, Newtonsoft.Json.Formatting.Indented);
//json = StringEncryption.EncryptDES(json); //加密
//写入文件
//string newJsonPath = Application.streamingAssetsPath + "/" + GetAssetPath(excelName + ".json");
string JsonPath = Path.Combine(AssetPath, fileName);
using (FileStream fileStream = new FileStream(JsonPath, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, encoding))
{
textWriter.Write(json);
}
}
}
}
///
/// 转换为lua
///
/// lua文件路径
public void ConvertToLua(string luaPath, Encoding encoding ,ref List fileNames)
{
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return;
//读取数据表
foreach (DataTable mSheet in mResultSet.Tables)
{
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
continue;
if (!mSheet.Rows[0][0].ToString().Equals("类名"))
continue;
string fileName = "test";
fileName = mSheet.Rows[1][0].ToString();
if (String.IsNullOrEmpty(fileName)) continue;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("local "+fileName+" = {");
stringBuilder.Append("\r\n");
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//准备一个列表存储整个表的数据
List> table = new List>();
//读取数据
for (int i = 2; i < rowCount; i++)
{
bool isNext = false;
for (int m = 0; m < colCount; m++)
{
string objStr = mSheet.Rows[i][m].ToString();
if (!string.IsNullOrEmpty(objStr) && objStr != "null")
{
isNext = true;
break;
}
}
if (!isNext) continue;
//准备一个字典存储每一行的数据
Dictionary row = new Dictionary();
for (int j = 1; j < colCount; j++)
{
//读取第1行数据作为表头字段
string field = mSheet.Rows[1][j].ToString();
//Key-Value对应
row[field] = mSheet.Rows[i][j];
}
//添加到表数据中
table.Add(row);
}
//stringBuilder.Append(string.Format("\t\"{0}\" = ", mSheet.TableName));
//stringBuilder.Append("{\r\n");
foreach (Dictionary dic in table)
{
stringBuilder.Append("\t\t{\r\n");
foreach (string key in dic.Keys)
{
if (string.IsNullOrEmpty(key)) continue;
object valueObj = dic[key];
Type type = valueObj.GetType();
if (valueObj.GetType().Name == "String")
{
string valueStr = valueObj as string;
string str = valueStr.Replace("\"", "\\\"");
if (!string.IsNullOrEmpty(valueStr))
stringBuilder.Append(string.Format("\t\t\t{0} = \"{1}\",\r\n", key, str));
else
stringBuilder.Append(string.Format("\t\t\t{0} = nil,\r\n", key));
}
else if (valueObj == null || valueObj.GetType().Name == "DBNull")
stringBuilder.Append(string.Format("\t\t\t{0} = nil,\r\n", key));
else
stringBuilder.Append(string.Format("\t\t\t{0} = {1},\r\n", key, valueObj));
}
stringBuilder.Append("\t\t},\r\n");
}
stringBuilder.Append("}\r\n");
stringBuilder.Append("_G."+fileName+" = "+ fileName);
stringBuilder.Append("\r\n");
stringBuilder.Append("setmetatable(_G," + fileName + ")");
stringBuilder.Append("\r\n");
stringBuilder.Append("return " + fileName);
fileNames.Add(fileName);
fileName += ".lua";
string writePath = Path.Combine(luaPath, fileName);
//写入文件
using (FileStream fileStream = new FileStream(writePath, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, encoding))
{
textWriter.Write(stringBuilder.ToString());
}
}
}
}
///
/// 转换为CSV
///
public void ConvertToCSV(string CSVPath, Encoding encoding)
{
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return;
//默认读取第一个数据表
DataTable mSheet = mResultSet.Tables[0];
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
return;
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//创建一个StringBuilder存储数据
StringBuilder stringBuilder = new StringBuilder();
//读取数据
for (int i = 0; i < rowCount; i++)
{
for (int j = 0; j < colCount; j++)
{
//使用","分割每一个数值
stringBuilder.Append(mSheet.Rows[i][j] + ",");
}
//使用换行符分割每一行
stringBuilder.Append("\r\n");
}
//写入文件
using (FileStream fileStream = new FileStream(CSVPath, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, encoding))
{
textWriter.Write(stringBuilder.ToString());
}
}
}
///
/// 导出为Xml
///
public void ConvertToXml(string XmlFile)
{
//判断Excel文件中是否存在数据表
if (mResultSet.Tables.Count < 1)
return;
//默认读取第一个数据表
DataTable mSheet = mResultSet.Tables[0];
//判断数据表内是否存在数据
if (mSheet.Rows.Count < 1)
return;
//读取数据表行数和列数
int rowCount = mSheet.Rows.Count;
int colCount = mSheet.Columns.Count;
//创建一个StringBuilder存储数据
StringBuilder stringBuilder = new StringBuilder();
//创建Xml文件头
stringBuilder.Append("");
stringBuilder.Append("\r\n");
//创建根节点
stringBuilder.Append("");
stringBuilder.Append("\r\n");
//读取数据
for (int i = 1; i < rowCount; i++)
{
//创建子节点
stringBuilder.Append(" ");
stringBuilder.Append("\r\n");
for (int j = 0; j < colCount; j++)
{
stringBuilder.Append(" <" + mSheet.Rows[0][j].ToString() + ">");
stringBuilder.Append(mSheet.Rows[i][j].ToString());
stringBuilder.Append("" + mSheet.Rows[0][j].ToString() + ">");
stringBuilder.Append("\r\n");
}
//使用换行符分割每一行
stringBuilder.Append("
");
stringBuilder.Append("\r\n");
}
//闭合标签
stringBuilder.Append("
");
//写入文件
using (FileStream fileStream = new FileStream(XmlFile, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, Encoding.GetEncoding("utf-8")))
{
textWriter.Write(stringBuilder.ToString());
}
}
}
///
/// 设置目标实例的属性
///
private void SetTargetProperty(object target, string propertyName, object propertyValue)
{
//获取类型
Type mType = target.GetType();
//获取属性集合
PropertyInfo[] mPropertys = mType.GetProperties();
foreach (PropertyInfo property in mPropertys)
{
if (property.Name == propertyName)
{
property.SetValue(target, Convert.ChangeType(propertyValue, property.PropertyType), null);
}
}
}
}
导出工具类ExcelTool代码如下:
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
public class ExcelTool
{
[MenuItem("Tools/读取配置文件")]
public static void CreateAndRead()
{
string assetPath = Path.Combine(Application.dataPath, "Res/JsonData");
Debug.Log($"Application.dataPath==={Application.dataPath}");
if (Directory.Exists(assetPath))
Directory.Delete(assetPath, true);
Directory.CreateDirectory(assetPath);
string path = Application.dataPath;
path = path.Replace("Assets", "GameData/");
List excels = new List();
var dirInfo = new DirectoryInfo(path);
foreach (FileInfo preaInfoFile in dirInfo.GetFiles("*.*", SearchOption.AllDirectories))
{
if (preaInfoFile.Name.EndsWith(".xlsx"))
{
//构造Excel工具类
ExcelUtility excel = new ExcelUtility(preaInfoFile.ToString());
//Encoding encoding = Encoding.GetEncoding("gb2312");
Encoding encoding = new UTF8Encoding();
excel.ConvertToJson(assetPath, encoding);
excels.Add(preaInfoFile.Name.Split('.')[0]);
}
}
Debug.Log("读取配置文件成功");
AssetDatabase.Refresh();
}
[MenuItem("Tools/读取配置文件Lua")]
public static void CreateLuaAndRead()
{
string assetPath = Path.Combine(Application.dataPath, "Lua/LuaData");
Debug.Log($"Application.dataPath==={Application.dataPath}");
if (Directory.Exists(assetPath))
Directory.Delete(assetPath, true);
Directory.CreateDirectory(assetPath);
string path = Application.dataPath;
path = path.Replace("Assets", "GameData/");
List excels = new List();
var dirInfo = new DirectoryInfo(path);
List luafileNames = new List();
foreach (FileInfo preaInfoFile in dirInfo.GetFiles("*.*", SearchOption.AllDirectories))
{
if (preaInfoFile.Name.EndsWith(".xlsx"))
{
//构造Excel工具类
ExcelUtility excel = new ExcelUtility(preaInfoFile.ToString());
//Encoding encoding = Encoding.GetEncoding("gb2312");
Encoding encoding = new UTF8Encoding();
excel.ConvertToLua(assetPath, encoding,ref luafileNames);
excels.Add(preaInfoFile.Name.Split('.')[0]);
}
}
CreateLuaData(assetPath, luafileNames);
Debug.Log("读取配置文件成功");
AssetDatabase.Refresh();
}
private static void CreateLuaData(string luaPath, List luafileNames)
{
string luaData = "LuaData.lua";
string writePath = Path.Combine(luaPath, luaData);
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < luafileNames.Count; i++)
{
string fileName = luafileNames[i];
stringBuilder.Append("require(\"LuaData."+ fileName+"\")");
stringBuilder.Append("\r\n");
}
//写入文件
using (FileStream fileStream = new FileStream(writePath, FileMode.Create, FileAccess.Write))
{
using (TextWriter textWriter = new StreamWriter(fileStream, new UTF8Encoding()))
{
textWriter.Write(stringBuilder.ToString());
}
}
}
}
导出的json如下:
[
{
"Lv": 1.0,
"price": "100000,0",
"speed": 3.0,
"volume": 1.0,
"icon": null
},
{
"Lv": 2.0,
"price": "1000000,0",
"speed": 3.0,
"volume": 2.0,
"icon": null
},
{
"Lv": 3.0,
"price": "10000000,0",
"speed": 3.0,
"volume": 3.0,
"icon": null
},
{
"Lv": 4.0,
"price": "50000000,0",
"speed": 3.0,
"volume": 4.0,
"icon": null
},
{
"Lv": 5.0,
"price": "50000000,1",
"speed": 3.0,
"volume": 5.0,
"icon": null
},
{
"Lv": 6.0,
"price": "50000000,2",
"speed": 3.0,
"volume": 6.0,
"icon": null
},
{
"Lv": 7.0,
"price": "50000000,3",
"speed": 3.0,
"volume": 7.0,
"icon": null
},
{
"Lv": 8.0,
"price": "50000000,4",
"speed": 3.0,
"volume": 8.0,
"icon": null
},
{
"Lv": 9.0,
"price": "50000000,5",
"speed": 3.0,
"volume": 9.0,
"icon": null
},
{
"Lv": 10.0,
"price": "50000000,6",
"speed": 3.0,
"volume": 10.0,
"icon": null
}
]
lua代码如下
local IdleTruckLv = {
{
Lv = 1,
price = "100000,0",
speed = 3,
volume = 1,
icon = nil,
},
{
Lv = 2,
price = "1000000,0",
speed = 3,
volume = 2,
icon = nil,
},
{
Lv = 3,
price = "10000000,0",
speed = 3,
volume = 3,
icon = nil,
},
{
Lv = 4,
price = "50000000,0",
speed = 3,
volume = 4,
icon = nil,
},
{
Lv = 5,
price = "50000000,1",
speed = 3,
volume = 5,
icon = nil,
},
{
Lv = 6,
price = "50000000,2",
speed = 3,
volume = 6,
icon = nil,
},
{
Lv = 7,
price = "50000000,3",
speed = 3,
volume = 7,
icon = nil,
},
{
Lv = 8,
price = "50000000,4",
speed = 3,
volume = 8,
icon = nil,
},
{
Lv = 9,
price = "50000000,5",
speed = 3,
volume = 9,
icon = nil,
},
{
Lv = 10,
price = "50000000,6",
speed = 3,
volume = 10,
icon = nil,
},
}
_G.IdleTruckLv = IdleTruckLv
setmetatable(_G,IdleTruckLv)
return IdleTruckLv
Demo下载地址:https://github.com/h1014179971/ExcelDemo