当前位置:   article > 正文

[Unity热更新]动态加载_instantiate和resources.load

instantiate和resources.load

参考链接:

http://www.xuanyusong.com/archives/1919


对于动态加载,主要有两种方式:

1.使用Resources.Load

2.使用AssetBundle


在游戏中,有一个很常见的情况:

有多个场景,且一开始时场景中角色和摄像机的位置旋转是不同的。如果我们把角色都放在场景,然后打包,明显是不对的(会增加apk的体积),所以需要把角色和场景分开,放在不同的包中。这时就需要根据配置信息来放置角色和摄像机的位置了。


生成配置文件:

  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEditor;
  4. using System.Collections.Generic;
  5. using System.Xml;
  6. using System.IO;
  7. using System.Text;
  8. using LitJson;
  9. public class ExportScene : Editor {
  10. //将所有游戏场景导出为XML格式
  11. [MenuItem ("Tool/ExportXML")]
  12. static void ExportXML ()
  13. {
  14. string filepath = Application.dataPath + @"/StreamingAssets/sceneInfoXML.xml";
  15. if(File.Exists (filepath))
  16. {
  17. File.Delete(filepath);
  18. }
  19. XmlDocument xmlDoc = new XmlDocument();
  20. XmlElement root = xmlDoc.CreateElement("scenes");
  21. //遍历所有的游戏场景
  22. foreach (UnityEditor.EditorBuildSettingsScene s in UnityEditor.EditorBuildSettings.scenes)
  23. {
  24. //当关卡启用
  25. if (s.enabled)
  26. {
  27. //得到关卡的名称
  28. string name = s.path;
  29. //打开这个关卡
  30. EditorApplication.OpenScene(name);
  31. XmlElement scene = xmlDoc.CreateElement("scene");
  32. scene.SetAttribute("name",name);
  33. foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
  34. {
  35. //因为场景内物体都制作为prefab,所以只需遍历父物体而无需遍历子物体(prefab已包含子物体的信息)
  36. if (obj.transform.parent == null)
  37. {
  38. XmlElement gameObject = xmlDoc.CreateElement("gameObject");
  39. gameObject.SetAttribute("name",obj.name);
  40. gameObject.SetAttribute("asset",obj.name + ".prefab");
  41. XmlElement transform = xmlDoc.CreateElement("transform");
  42. XmlElement position = xmlDoc.CreateElement("position");
  43. XmlElement position_x = xmlDoc.CreateElement("x");
  44. position_x.InnerText = obj.transform.position.x+"";
  45. XmlElement position_y = xmlDoc.CreateElement("y");
  46. position_y.InnerText = obj.transform.position.y+"";
  47. XmlElement position_z = xmlDoc.CreateElement("z");
  48. position_z.InnerText = obj.transform.position.z+"";
  49. position.AppendChild(position_x);
  50. position.AppendChild(position_y);
  51. position.AppendChild(position_z);
  52. XmlElement rotation = xmlDoc.CreateElement("rotation");
  53. XmlElement rotation_x = xmlDoc.CreateElement("x");
  54. rotation_x.InnerText = obj.transform.rotation.eulerAngles.x+"";
  55. XmlElement rotation_y = xmlDoc.CreateElement("y");
  56. rotation_y.InnerText = obj.transform.rotation.eulerAngles.y+"";
  57. XmlElement rotation_z = xmlDoc.CreateElement("z");
  58. rotation_z.InnerText = obj.transform.rotation.eulerAngles.z+"";
  59. rotation.AppendChild(rotation_x);
  60. rotation.AppendChild(rotation_y);
  61. rotation.AppendChild(rotation_z);
  62. XmlElement scale = xmlDoc.CreateElement("scale");
  63. XmlElement scale_x = xmlDoc.CreateElement("x");
  64. scale_x.InnerText = obj.transform.localScale.x+"";
  65. XmlElement scale_y = xmlDoc.CreateElement("y");
  66. scale_y.InnerText = obj.transform.localScale.y+"";
  67. XmlElement scale_z = xmlDoc.CreateElement("z");
  68. scale_z.InnerText = obj.transform.localScale.z+"";
  69. scale.AppendChild(scale_x);
  70. scale.AppendChild(scale_y);
  71. scale.AppendChild(scale_z);
  72. transform.AppendChild(position);
  73. transform.AppendChild(rotation);
  74. transform.AppendChild(scale);
  75. gameObject.AppendChild(transform);
  76. scene.AppendChild(gameObject);
  77. root.AppendChild(scene);
  78. xmlDoc.AppendChild(root);
  79. xmlDoc.Save(filepath);
  80. }
  81. }
  82. }
  83. }
  84. //刷新Project视图, 不然需要手动刷新哦
  85. AssetDatabase.Refresh();
  86. }
  87. //将所有游戏场景导出为JSON格式
  88. [MenuItem ("Tool/ExportJSON")]
  89. static void ExportJSON ()
  90. {
  91. string filepath = Application.dataPath + @"/StreamingAssets/sceneInfoJSON.txt";
  92. FileInfo t = new FileInfo(filepath);
  93. if(File.Exists (filepath))
  94. {
  95. File.Delete(filepath);
  96. }
  97. StreamWriter sw = t.CreateText();
  98. StringBuilder sb = new StringBuilder ();
  99. JsonWriter writer = new JsonWriter (sb);
  100. writer.WriteObjectStart ();
  101. writer.WritePropertyName ("scenes");
  102. writer.WriteArrayStart ();
  103. foreach (UnityEditor.EditorBuildSettingsScene s in UnityEditor.EditorBuildSettings.scenes)
  104. {
  105. if (s.enabled)
  106. {
  107. string name = s.path;
  108. EditorApplication.OpenScene(name);
  109. writer.WriteObjectStart();
  110. writer.WritePropertyName("scene");
  111. writer.WriteObjectStart();
  112. writer.WritePropertyName("name");
  113. writer.Write(name);
  114. writer.WritePropertyName("gameObjects");
  115. writer.WriteArrayStart ();
  116. foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
  117. {
  118. if (obj.transform.parent == null)
  119. {
  120. writer.WriteObjectStart();
  121. writer.WritePropertyName("name");
  122. writer.Write(obj.name);
  123. writer.WritePropertyName("position");
  124. writer.WriteArrayStart ();
  125. writer.WriteObjectStart();
  126. writer.WritePropertyName("x");
  127. writer.Write(obj.transform.position.x.ToString("F5"));
  128. writer.WritePropertyName("y");
  129. writer.Write(obj.transform.position.y.ToString("F5"));
  130. writer.WritePropertyName("z");
  131. writer.Write(obj.transform.position.z.ToString("F5"));
  132. writer.WriteObjectEnd();
  133. writer.WriteArrayEnd();
  134. writer.WritePropertyName("rotation");
  135. writer.WriteArrayStart ();
  136. writer.WriteObjectStart();
  137. writer.WritePropertyName("x");
  138. writer.Write(obj.transform.rotation.eulerAngles.x.ToString("F5"));
  139. writer.WritePropertyName("y");
  140. writer.Write(obj.transform.rotation.eulerAngles.y.ToString("F5"));
  141. writer.WritePropertyName("z");
  142. writer.Write(obj.transform.rotation.eulerAngles.z.ToString("F5"));
  143. writer.WriteObjectEnd();
  144. writer.WriteArrayEnd();
  145. writer.WritePropertyName("scale");
  146. writer.WriteArrayStart ();
  147. writer.WriteObjectStart();
  148. writer.WritePropertyName("x");
  149. writer.Write(obj.transform.localScale.x.ToString("F5"));
  150. writer.WritePropertyName("y");
  151. writer.Write(obj.transform.localScale.y.ToString("F5"));
  152. writer.WritePropertyName("z");
  153. writer.Write(obj.transform.localScale.z.ToString("F5"));
  154. writer.WriteObjectEnd();
  155. writer.WriteArrayEnd();
  156. writer.WriteObjectEnd();
  157. }
  158. }
  159. writer.WriteArrayEnd();//end gameObjects
  160. writer.WriteObjectEnd();//end name
  161. writer.WriteObjectEnd();//end scene
  162. }
  163. }
  164. writer.WriteArrayEnd();//end scenes
  165. writer.WriteObjectEnd ();//end root
  166. sw.WriteLine(sb.ToString());
  167. sw.Close();
  168. sw.Dispose();
  169. AssetDatabase.Refresh();
  170. }
  171. //将所有游戏场景导出为Binary格式
  172. [MenuItem ("Tool/ExportBinary")]
  173. static void ExportBinary ()
  174. {
  175. string filepath = Application.dataPath + @"/StreamingAssets/sceneInfoBinary.txt";
  176. if(File.Exists (filepath))
  177. {
  178. File.Delete(filepath);
  179. }
  180. FileStream fs = new FileStream(filepath, FileMode.Create);
  181. BinaryWriter bw = new BinaryWriter(fs);
  182. foreach (UnityEditor.EditorBuildSettingsScene s in UnityEditor.EditorBuildSettings.scenes)
  183. {
  184. if (s.enabled)
  185. {
  186. string sceneName = s.path;
  187. EditorApplication.OpenScene(sceneName);
  188. bw.Write(sceneName);
  189. foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
  190. {
  191. if (obj.transform.parent == null)
  192. {
  193. bw.Write(obj.name);
  194. //将float转化为short,这样传输的字节数就会变少
  195. //接收时将short转化为float就可以了
  196. bw.Write((short)(obj.transform.position.x * 100));
  197. bw.Write((short)(obj.transform.position.y * 100));
  198. bw.Write((short)(obj.transform.position.z * 100));
  199. bw.Write((short)(obj.transform.rotation.eulerAngles.x * 100));
  200. bw.Write((short)(obj.transform.rotation.eulerAngles.y * 100));
  201. bw.Write((short)(obj.transform.rotation.eulerAngles.z * 100));
  202. bw.Write((short)(obj.transform.localScale.x * 100));
  203. bw.Write((short)(obj.transform.localScale.y * 100));
  204. bw.Write((short)(obj.transform.localScale.z * 100));
  205. }
  206. }
  207. }
  208. }
  209. bw.Flush();
  210. bw.Close();
  211. fs.Close();
  212. AssetDatabase.Refresh();
  213. }
  214. }

读取配置文件:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Xml;
  4. using System.IO;
  5. //建立一个空物体,然后挂上此脚本
  6. public class ResolveSceneInfoXML : MonoBehaviour {
  7. // Use this for initialization
  8. void Start ()
  9. {
  10. //电脑和iphone上的路径是不一样的,这里用标签判断一下。
  11. #if UNITY_EDITOR
  12. string filepath = Application.dataPath +"/StreamingAssets"+"/sceneInfoXML.xml";
  13. #elif UNITY_IPHONE
  14. string filepath = Application.dataPath +"/Raw"+"/sceneInfoXML.xml";
  15. #endif
  16. //如果文件存在话开始解析。
  17. if(File.Exists (filepath))
  18. {
  19. XmlDocument xmlDoc = new XmlDocument();
  20. xmlDoc.Load(filepath);
  21. XmlNodeList nodeList = xmlDoc.SelectSingleNode("scenes").ChildNodes;
  22. foreach(XmlElement scene in nodeList)
  23. {
  24. //因为我的XML是把所有游戏对象全部导出, 所以这里判断一下只解析需要的场景中的游戏对象
  25. //JSON和它的原理类似
  26. if(!scene.GetAttribute("name").Equals("Assets/s1.unity"))
  27. {
  28. continue;
  29. }
  30. //prefab放置在Resources/Prefab文件夹下
  31. //遍历所有gameobject
  32. foreach(XmlElement gameObject in scene.ChildNodes)
  33. {
  34. string asset = "Prefab/" + gameObject.GetAttribute("name");
  35. Vector3 pos = Vector3.zero;
  36. Vector3 rot = Vector3.zero;
  37. Vector3 sca = Vector3.zero;
  38. XmlNode transform = gameObject.SelectSingleNode("transform");
  39. foreach(XmlElement prs in transform.ChildNodes)
  40. {
  41. if(prs.Name == "position")
  42. {
  43. foreach(XmlElement position in prs.ChildNodes)
  44. {
  45. switch(position.Name)
  46. {
  47. case "x":
  48. pos.x = float.Parse(position.InnerText);
  49. break;
  50. case "y":
  51. pos.y = float.Parse(position.InnerText);
  52. break;
  53. case "z":
  54. pos.z = float.Parse(position.InnerText);
  55. break;
  56. }
  57. }
  58. }else if(prs.Name == "rotation")
  59. {
  60. foreach(XmlElement rotation in prs.ChildNodes)
  61. {
  62. switch(rotation.Name)
  63. {
  64. case "x":
  65. rot.x = float.Parse(rotation.InnerText);
  66. break;
  67. case "y":
  68. rot.y = float.Parse(rotation.InnerText);
  69. break;
  70. case "z":
  71. rot.z = float.Parse(rotation.InnerText);
  72. break;
  73. }
  74. }
  75. }else if(prs.Name == "scale")
  76. {
  77. foreach(XmlElement scale in prs.ChildNodes)
  78. {
  79. switch(scale.Name)
  80. {
  81. case "x":
  82. sca.x = float.Parse(scale.InnerText);
  83. break;
  84. case "y":
  85. sca.y = float.Parse(scale.InnerText);
  86. break;
  87. case "z":
  88. sca.z = float.Parse(scale.InnerText);
  89. break;
  90. }
  91. }
  92. }
  93. }
  94. //拿到 旋转 缩放 平移 以后克隆新游戏对象
  95. GameObject ob = (GameObject)Instantiate(Resources.Load(asset),pos,Quaternion.Euler(rot));
  96. ob.transform.localScale = sca;
  97. }
  98. }
  99. }
  100. }
  101. }

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.IO;
  4. using LitJson;
  5. public class ResolveSceneInfoJSON : MonoBehaviour {
  6. // Use this for initialization
  7. void Start ()
  8. {
  9. #if UNITY_EDITOR
  10. string filepath = Application.dataPath +"/StreamingAssets"+"/sceneInfoJSON.txt";
  11. #elif UNITY_IPHONE
  12. string filepath = Application.dataPath +"/Raw"+"/json.txt";
  13. #endif
  14. StreamReader sr = File.OpenText(filepath);
  15. string strLine = sr.ReadToEnd();
  16. JsonData jd = JsonMapper.ToObject(strLine);
  17. JsonData scenes = jd["scenes"];
  18. int i,j;
  19. for (i = 0; i < scenes.Count; i++)
  20. {
  21. JsonData scene = scenes[i]["scene"];
  22. string sceneName = (string)scene["name"];
  23. if(!sceneName.Equals("Assets/s1.unity"))
  24. {
  25. continue;
  26. }
  27. JsonData gameObjects = scene["gameObjects"];
  28. for (j = 0; j < gameObjects.Count; j++)
  29. {
  30. string objectName = (string)gameObjects[j]["name"];
  31. string asset = "Prefab/" + objectName;
  32. Vector3 pos = Vector3.zero;
  33. Vector3 rot = Vector3.zero;
  34. Vector3 sca = Vector3.zero;
  35. JsonData position = gameObjects[j]["position"];
  36. JsonData rotation = gameObjects[j]["rotation"];
  37. JsonData scale = gameObjects[j]["scale"];
  38. pos.x = float.Parse((string)position[0]["x"]);
  39. pos.y = float.Parse((string)position[0]["y"]);
  40. pos.z = float.Parse((string)position[0]["z"]);
  41. rot.x = float.Parse((string)rotation[0]["x"]);
  42. rot.y = float.Parse((string)rotation[0]["y"]);
  43. rot.z = float.Parse((string)rotation[0]["z"]);
  44. sca.x = float.Parse((string)scale[0]["x"]);
  45. sca.y = float.Parse((string)scale[0]["y"]);
  46. sca.z = float.Parse((string)scale[0]["z"]);
  47. GameObject go = (GameObject)Instantiate(Resources.Load(asset),pos,Quaternion.Euler(rot));
  48. go.transform.localScale = sca;
  49. }
  50. }
  51. }
  52. }

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.IO;
  4. using System.Text;
  5. using System;
  6. public class ResolveSceneInfoBinary : MonoBehaviour {
  7. // Use this for initialization
  8. void Start ()
  9. {
  10. string filepath = Application.dataPath + @"/StreamingAssets/sceneInfoBinary.txt";
  11. if (File.Exists (filepath))
  12. {
  13. FileStream fs = new FileStream (filepath, FileMode.Open);
  14. BinaryReader br = new BinaryReader (fs);
  15. string sceneName = br.ReadString();
  16. while(fs.Position < fs.Length)
  17. {
  18. string objName = br.ReadString();
  19. float px = br.ReadInt16() / 100f;
  20. float py = br.ReadInt16() / 100f;
  21. float pz = br.ReadInt16() / 100f;
  22. float rx = br.ReadInt16() / 100f;
  23. float ry = br.ReadInt16() / 100f;
  24. float rz = br.ReadInt16() / 100f;
  25. float sx = br.ReadInt16() / 100f;
  26. float sy = br.ReadInt16() / 100f;
  27. float sz = br.ReadInt16() / 100f;
  28. string asset = "Prefab/" + objName;
  29. Vector3 pos = new Vector3 (px,py,pz);
  30. Vector3 rot = new Vector3(rx,ry,rz);
  31. Vector3 sca = new Vector3(sx,sy,sz);
  32. GameObject go = (GameObject)Instantiate(Resources.Load(asset),pos,Quaternion.Euler(rot));
  33. go.transform.localScale = sca;
  34. }
  35. }
  36. }
  37. }


上面使用的是Resources.Load,下面就使用AssetBundle吧!这里本人使用的是unity5的打包系统,先从本地服务器下载AB包到本地,再加载。

测试场景很简单,AB包有六个:总的AB包,3个物体的包,cube的材质,材质的纹理,下载后就把文件放在Application.streamingAssetsPath下,加载时就加载camera、cube和灯光。服务器是tomcat服务器,当然也可以跳过下载的过程,直接本地加载AB包。要注意的是,测试最好使用new WWW,而不是WWW.LoadFromCacheOrDownload,因为LoadFromCacheOrDownload需要提供一个版本号,如果不更改版本号就不会下载新的AB包了。




创建AB:

  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEditor;
  4. /*
  5. * 注意:
  6. * 1.prefab的名称以及生成的AB包的名称最好不要带空格,否则从服务器下载AB包时,下载到本地的AB包可能为空。
  7. * 2.prefab的名称最好全部小写,因为在设置AB包的名称时,unity会将设置的名称全部改为小写。
  8. * 这样prefab的名称就可以与AB包的名称一一对应了
  9. */
  10. public class CreateAssetBundle : Editor {
  11. [MenuItem("Tool/SetFileBundleName")]
  12. static void SetBundleName()
  13. {
  14. #region 设置资源的AssetBundle的名称和文件扩展名
  15. UnityEngine.Object[] selects = Selection.objects;
  16. foreach (UnityEngine.Object selected in selects)
  17. {
  18. string path = AssetDatabase.GetAssetPath(selected);
  19. AssetImporter asset = AssetImporter.GetAtPath(path);
  20. asset.assetBundleName = selected.name; //设置Bundle文件的名称
  21. asset.assetBundleVariant = "unity3d";//设置Bundle文件的扩展名
  22. asset.SaveAndReimport();
  23. }
  24. AssetDatabase .Refresh();
  25. #endregion
  26. }
  27. [MenuItem("Tool/BuildAll")]
  28. static void Build()
  29. {
  30. BuildPipeline.BuildAssetBundles(Application.dataPath + "/AB");
  31. }
  32. }

下载AB:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.IO;
  4. using System.Text;
  5. [RequireComponent(typeof(LoadAssetbBundle))]
  6. public class DownLoadAssetbBundle : MonoBehaviour {
  7. //要下载的AB包
  8. string[] s = new string[]{"AB","directionallight","cube","camera","m1","t1"};
  9. // Use this for initialization
  10. void Start ()
  11. {
  12. //print (Application.dataPath);
  13. //print (Application.persistentDataPath);
  14. //print (Application.streamingAssetsPath);
  15. //print (Application.temporaryCachePath);
  16. StartCoroutine (DownLoad(s));
  17. }
  18. IEnumerator DownLoad(string[] assetBundleNames)
  19. {
  20. FileStream fs = null;
  21. for (int i = 0; i < assetBundleNames.Length; i++)
  22. {
  23. string savePath;
  24. string url;
  25. if(assetBundleNames[i].Equals("AB"))
  26. {
  27. savePath = Application.streamingAssetsPath + "/" + assetBundleNames[i];
  28. url = "http://172.25.225.24:8080/UpdateServer" + "/" + assetBundleNames[i];
  29. }
  30. else
  31. {
  32. savePath = Application.streamingAssetsPath + "/" + assetBundleNames[i] + ".unity3d";
  33. url = "http://172.25.225.24:8080/UpdateServer" + "/" + assetBundleNames[i] + ".unity3d";
  34. }
  35. //如果不存在则下载AB,并保存到指定文件夹中
  36. if (!File.Exists (savePath))
  37. {
  38. fs = new FileStream(savePath, FileMode.Create);
  39. WWW www = new WWW (url);
  40. yield return www;
  41. byte[] bytes = www.bytes;
  42. print(assetBundleNames[i] + " " + bytes.Length);
  43. fs.Write(bytes,0,bytes.Length);
  44. }
  45. }
  46. if (fs != null)
  47. {
  48. fs.Close ();
  49. fs.Dispose ();
  50. }
  51. //加载AB
  52. LoadAssetbBundle lab = GetComponent<LoadAssetbBundle> ();
  53. if (lab != null)
  54. {
  55. lab.StartLoad("file://" + Application.streamingAssetsPath + "/",
  56. new string[] { "camera", "cube", "directionallight"});//要加载的AB包
  57. }
  58. }
  59. }

加载AB:

  1. using UnityEngine;
  2. using System.Collections;
  3. public class LoadAssetbBundle : MonoBehaviour {
  4. public void StartLoad(string assetBundlePath, string[] assetBundleNames)
  5. {
  6. StartCoroutine(LoadGo(assetBundlePath,assetBundleNames));
  7. }
  8. /*
  9. * assetBundlePath:Assetbundle的文件夹,末尾要加"/"
  10. * assetBundleNames:要加载的AssetBundle的名字,不用加后缀
  11. * 注意:www需要加后缀,而AssetBundle.LoadAsset不需要
  12. * */
  13. IEnumerator LoadGo(string assetBundlePath, string[] assetBundleNames)
  14. {
  15. AssetBundleManifest manifest = null;
  16. //首先加载Manifest文件;
  17. WWW mwww = new WWW(assetBundlePath + "AB");
  18. yield return mwww;
  19. if (!string.IsNullOrEmpty (mwww.error))
  20. {
  21. Debug.LogError (mwww.error);
  22. }
  23. else
  24. {
  25. AssetBundle ab = mwww.assetBundle;
  26. manifest = (AssetBundleManifest)ab.LoadAsset ("AssetBundleManifest");
  27. ab.Unload (false);
  28. }
  29. for (int i = 0; i < assetBundleNames.Length; i++)
  30. {
  31. //获取依赖文件列表;
  32. string[] depends = manifest.GetAllDependencies(assetBundleNames[i] + ".unity3d");
  33. AssetBundle[] dependsAssetBundle = new AssetBundle[depends.Length];
  34. for(int index = 0;index < depends.Length;index++)
  35. {
  36. //加载所有的依赖文件;
  37. WWW dwww = new WWW(assetBundlePath + depends[index]);
  38. yield return dwww;
  39. dependsAssetBundle[index] = dwww.assetBundle;
  40. }
  41. //加载我们需要的文件;
  42. WWW gowww = new WWW(assetBundlePath + assetBundleNames[i] + ".unity3d");
  43. yield return gowww;
  44. if(!string.IsNullOrEmpty(gowww.error))
  45. {
  46. Debug.LogError(gowww.error);
  47. }
  48. else
  49. {
  50. AssetBundle goAB = gowww.assetBundle;
  51. GameObject go = goAB.LoadAsset(assetBundleNames[i]) as GameObject;
  52. if(go != null)
  53. {
  54. Instantiate(go);
  55. }
  56. goAB.Unload(false);
  57. }
  58. //卸载依赖文件的包
  59. for(int index = 0;index < depends.Length;index++)
  60. {
  61. dependsAssetBundle[index].Unload(false);
  62. }
  63. }
  64. }
  65. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/566369
推荐阅读
相关标签
  

闽ICP备14008679号