AlertCtrl.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. const JMAlertBase = require('JMAlertBase');
  2. /**
  3. * 弹框控制器
  4. */
  5. cc.Class({
  6. extends: cc.Component,
  7. properties: {
  8. _alertList: {
  9. default: [],
  10. type: JMAlertBase
  11. }
  12. },
  13. /**
  14. * 生命周期。子类需要调用this._super()
  15. *
  16. * @author Pyden
  17. * @date 2019-03-25
  18. */
  19. onEnable () {
  20. this.node.on('e_alert_pop', this._handlePopAlert, this);
  21. },
  22. /**
  23. * 生命周期。子类需要调用this._super()
  24. *
  25. * @author Pyden
  26. * @date 2019-03-25
  27. */
  28. onDisable () {
  29. this.node.off('e_alert_pop', this._handlePopAlert, this);
  30. },
  31. /**
  32. * 返回键被点击。最后一个弹框会吃掉返回键响应
  33. *
  34. * @author Pyden
  35. * @date 2019-03-25
  36. * @returns 是否吃点返回键响应
  37. */
  38. backKeyOnClicked () {
  39. let length = this._alertList.length;
  40. if (length > 0) {
  41. let alert = this._alertList[length - 1];
  42. alert.backKeyOnClicked();
  43. return true;
  44. } else {
  45. return false;
  46. }
  47. },
  48. /**
  49. * 弹出指定弹框
  50. *
  51. * @author Pyden
  52. * @date 2019-03-22
  53. * @param {JMAlertBase} alert 弹框
  54. */
  55. pushAlert (alert) {
  56. if (!cc.isValid(alert) || !cc.isValid(this.node)) {
  57. return false;
  58. }
  59. let zIndex = alert.alertZIndex;
  60. this.node.addChild(alert.node, zIndex);
  61. this._alertList.push(alert);
  62. cc.game.emit('e_ui_push_alert', {alert: alert});
  63. return true;
  64. },
  65. /**
  66. * 关闭指定弹框
  67. *
  68. * @author Pyden
  69. * @date 2019-03-22
  70. * @param {JMAlertBase} alert 弹框
  71. */
  72. popAlert (alert) {
  73. let length = this._alertList.length;
  74. for (let i = length - 1; i >= 0; i--) {
  75. if (this._alertList[i] === alert) {
  76. this._alertList.splice(i, 1);
  77. break;
  78. }
  79. }
  80. alert.node.destroy();
  81. let topAlert = this._alertList[this._alertList.length - 1];
  82. cc.game.emit('e_ui_pop_alert', {alertId: alert.id, alertData: alert.data, topAlert: topAlert});
  83. },
  84. /**
  85. * 关闭全部弹框
  86. * 不能在hideDone的触发事件中调用popAllAlert
  87. * 会造成栈溢出,需要加个scheduleOnce避免无限递归调用
  88. *
  89. * @author Pyden
  90. * @date 2019-03-22
  91. * @param {boolean} forceClose 强制关闭
  92. */
  93. popAllAlert (forceClose) {
  94. let length = this._alertList.length;
  95. for (let i = length - 1; i >= 0; i--) {
  96. let alert = this._alertList[i];
  97. if (alert.alertZIndex < 100 || forceClose) {
  98. alert.close();
  99. }
  100. }
  101. },
  102. /**
  103. * 关闭指定弹框
  104. *
  105. * @author Wetion
  106. * @date 2019-05-23
  107. * @param {Number} alertId 弹框ID
  108. */
  109. closeAlert (alertId) {
  110. let length = this._alertList.length;
  111. for (let i = length - 1; i >= 0; i--) {
  112. let alert = this._alertList[i];
  113. if (alert.id === alertId) {
  114. alert.close();
  115. break;
  116. }
  117. }
  118. },
  119. /**
  120. * 获取已弹出的弹框
  121. *
  122. * @author Pyden
  123. * @date 2019-03-28
  124. * @param {JMC.ALERT_ID} alertId 弹框 Id
  125. * @returns {JMAlertBase} 弹框组件
  126. */
  127. getAlert (alertId) {
  128. for (let v of this._alertList) {
  129. if (v.id == alertId) {
  130. return v;
  131. }
  132. }
  133. return undefined;
  134. },
  135. /**
  136. * 获取已弹出的弹窗数量
  137. *
  138. * @author libo
  139. * @date 2019-05-05
  140. * @returns number 弹窗数量
  141. */
  142. getAlertCount () {
  143. return this._alertList.length;
  144. },
  145. /**
  146. * 弹出普通弹框
  147. *
  148. * @author Pyden
  149. * @date 2019-03-28
  150. * @param {JMC.ALERT_ID} alertId 弹框 Id
  151. * @param {any} userdata 弹框相关的数据
  152. * @param {function} cb 回调,参数有:alert, eventKey, eventData。cb为空时,点击弹框任意交互都关闭弹框
  153. * @example
  154. ```js
  155. let alertId = JMC.ALERT_ID.ITEM_INFO;
  156. let userdata = {param1: 1, param2: 2, goodsData: goodsData};
  157. let cb = (alert, eventKey, eventData) => {
  158. if (eventKey == 'clickedLeft') {
  159. // 左边按钮点击
  160. } else if (eventKey == 'clickedRight') {
  161. // 右边按钮点击
  162. } else {
  163. // 事件的默认处理:忽略 error、willShow 时间,其它事件都直接关闭弹框
  164. alert.alertDefaultCallback(eventKey, eventData);
  165. }
  166. };
  167. this.showNormalAlert(alertId, userdata, cb);
  168. */
  169. showNormalAlert (alertId, userdata, cb) {
  170. let alertData = G.AlertMgr.getConfig(alertId, userdata);
  171. this.showAlert(
  172. 'edt_prefab/public/prefab_normal_alert',
  173. alertData,
  174. cb,
  175. true
  176. );
  177. },
  178. /**
  179. * 弹出弹框
  180. *
  181. * @author Pyden
  182. * @date 2019-04-12
  183. * @param {String} prefabPath 预制体的路径
  184. * @param {Object} alertData 弹框的数据,用在reloadData
  185. * @param {Function} cb 回调,参数有:alert, eventKey, eventData。cb为空时,点击弹框任意交互都关闭弹框
  186. * @example
  187. ```js
  188. let alertId = JMC.ALERT_ID.ITEM_INFO;
  189. let userdata = {param1: 1, param2: 2, goodsData: goodsData};
  190. let alertData = G.AlertMgr.getConfig(alertId, userdata);
  191. let cb = (alert, eventKey, eventData) => {
  192. if (eventKey == 'clickedLeft') {
  193. // 左边按钮点击
  194. } else if (eventKey == 'clickedRight') {
  195. // 右边按钮点击
  196. } else {
  197. // 事件的默认处理:忽略 error、willShow 时间,其它事件都直接关闭弹框
  198. alert.alertDefaultCallback(eventKey, eventData);
  199. }
  200. };
  201. this.showAlert(
  202. 'edt_prefab/public/prefab_normal_alert',
  203. alertData,
  204. cb
  205. );
  206. */
  207. showAlert (prefabPath, alertData, cb, cache = false) {
  208. G.LogUtils.warn('showAlert', prefabPath);
  209. G.AppUtils.getSceneCtrl().showLoadingAlert();
  210. let temp = undefined;
  211. cc.loader.loadRes(prefabPath, cc.Prefab, (completedCount, totalCount, item)=>{
  212. temp = G.AppUtils.getLoadProgressInfo(temp, completedCount, totalCount);
  213. G.AppUtils.getSceneCtrl().updateLoadingProgress(temp.precent * 100, 100, item);
  214. }, (err, prefab) => {
  215. G.AppUtils.getSceneCtrl().updateLoadingProgress(100, 100, undefined);
  216. if (err) {
  217. G.AppUtils.getSceneCtrl().addToast('网络异常!');
  218. G.LogUtils.error('[showAlert]', err);
  219. if (cb) {
  220. cb(undefined, 'error', err);
  221. }
  222. return;
  223. }
  224. let node = cc.instantiate(prefab);
  225. let alert = node.getComponent('JMAlertBase');
  226. if (cb) {
  227. cb(alert, 'willShow', undefined);
  228. }
  229. let ret = this.pushAlert(alert);
  230. if (!ret) {
  231. return;
  232. }
  233. // 因为reloadData如果出错会导致游戏闪屏,所以加上try catch
  234. try {
  235. alert.reloadData(alertData, cb);
  236. } catch (error) {
  237. G.LogUtils.error('AlertCtrl showAlert error:', error);
  238. }
  239. if (!cache) {
  240. cc.loader.releaseRes(prefabPath);
  241. }
  242. });
  243. },
  244. // ---------------- 私有方法分割线 ----------------
  245. /**
  246. * 收到弹框关闭的事件。只能收到子节点的事件
  247. *
  248. * @author Pyden
  249. * @date 2019-03-25
  250. * @param {cc.Event} event
  251. */
  252. _handlePopAlert (event) {
  253. let alert = event.getUserData();
  254. this.popAlert(alert);
  255. }
  256. });