|
@@ -0,0 +1,410 @@
|
|
|
+'use strict';
|
|
|
+
|
|
|
+const logger = require('Logger').getLogger('Navigator.js');
|
|
|
+
|
|
|
+
|
|
|
+ * 导航模式
|
|
|
+ * @type {{New: number, Back: number, Refresh: number}}
|
|
|
+ */
|
|
|
+const navigatorMode = {
|
|
|
+ New: 0,
|
|
|
+ Back: 1,
|
|
|
+ Refresh: 2
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+ * Navigator介绍:
|
|
|
+ * ------------------------
|
|
|
+ * 提供一个支持导航栈的Navigator类,支持以下特性
|
|
|
+ * 0,记录场景切换的导航栈。
|
|
|
+ * 1,场景之间可以传递参数,比如场景A要传个字符串给场景B。
|
|
|
+ * 2,多个场景进入同一场景后,从场景返回前一个场景,不需要再判断前一个场景,可以直接goBack返回。
|
|
|
+ * 3,支持场景返回后页面数据恢复,比如场景A界面,输入框输入了一段文字,然后进入场景B,
|
|
|
+ * 从场景B返回后可以恢复输入框文字(需要在场景A脚本实现固定接口支持)。
|
|
|
+ *
|
|
|
+ * Navigator使用方法:
|
|
|
+ * ------------------------
|
|
|
+ * a)在场景A向前加载新场景B[带参数][带回调]
|
|
|
+ *
|
|
|
+ * navigator.navigate('B');
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * let parameter = {};
|
|
|
+ * parameter.title = 'i am wang ronghui';
|
|
|
+ * navigator.navigate('B', parameter);
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * navigator.navigate('B', function(scene){
|
|
|
+ *
|
|
|
+ * });
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * let parameter = {};
|
|
|
+ * parameter.title = 'i am wang ronghui';
|
|
|
+ * navigator.navigate('B', parameter, function(scene){
|
|
|
+ *
|
|
|
+ * });
|
|
|
+ *
|
|
|
+ * ~如果有传递parameter需在相应B.js内部实现loadState(navigatorMode, parameter, state)函数接收参数parameter。
|
|
|
+ * ~如果要存储当前UI状态则实现saveState(state){
|
|
|
+ *
|
|
|
+ * c)场景B向后返回前一个场景A
|
|
|
+ *
|
|
|
+ * navigator.goBack();
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * let parameter = {};
|
|
|
+ * parameter.title = 'i am wang ronghui';
|
|
|
+ * navigator.goBack(parameter);
|
|
|
+ *
|
|
|
+ * d)场景B向后返回指定名字场景A
|
|
|
+ *
|
|
|
+ * navigator.goBackToScene('A');
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * let parameter = {};
|
|
|
+ * parameter.title = 'i am wang ronghui';
|
|
|
+ * navigator.goBackToScene('A', parameter);
|
|
|
+ *
|
|
|
+ * e)场景B向后返回根场景
|
|
|
+ *
|
|
|
+ * navigator.goBackToRootScene();
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * let parameter = {};
|
|
|
+ * parameter.title = 'i am wang ronghui';
|
|
|
+ * navigator.goBackToRootScene(parameter);
|
|
|
+ *
|
|
|
+ * 注意事项:
|
|
|
+ * ------------------------
|
|
|
+ * 挂载到场景的Canvas的自定义脚本的名字,必须要和场景文件的名字一致,否则无法调用到loadState或者saveState
|
|
|
+ *
|
|
|
+ */
|
|
|
+class Navigator
|
|
|
+{
|
|
|
+
|
|
|
+ * 构造方法
|
|
|
+ */
|
|
|
+ constructor(){
|
|
|
+ logger.info('constructor');
|
|
|
+
|
|
|
+ this._allState = new Map();
|
|
|
+ this._scenesStack = [];
|
|
|
+ this._sceneLaunchHandle = false;
|
|
|
+
|
|
|
+
|
|
|
+ * 支持外部使用cc.director.loadScene直接导航,记录下导航栈
|
|
|
+ */
|
|
|
+ cc.director.on(cc.Director.EVENT_AFTER_SCENE_LAUNCH, function (eventCustom) {
|
|
|
+
|
|
|
+ if(this._sceneLaunchHandle) {
|
|
|
+ this._sceneLaunchHandle = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let sceneName = eventCustom.name;
|
|
|
+ logger.info('EVENT_AFTER_SCENE_LAUNCH sceneName = ' + sceneName);
|
|
|
+
|
|
|
+
|
|
|
+ let level = this.sceneStackLevel(sceneName);
|
|
|
+ if(level !== -1){
|
|
|
+ this.goBackToSceneStackLevel(level, null);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.handleForward(sceneName, null);
|
|
|
+ }.bind(this));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 向前加载sceneName场景
|
|
|
+ * @param {string} sceneName -场景名字
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ * @param {function()} [onSceneLaunched] -新场景运行成功后回调
|
|
|
+ */
|
|
|
+ navigate(sceneName, parameter, onSceneLaunched){
|
|
|
+ logger.info('navigate sceneName = ' + sceneName);
|
|
|
+ logger.log('navigate parameter = ' + parameter);
|
|
|
+ logger.log('navigate onSceneLaunched = ' + onSceneLaunched);
|
|
|
+
|
|
|
+
|
|
|
+ let argsLength = arguments.length;
|
|
|
+ if(argsLength === 2) {
|
|
|
+ if (typeof parameter === 'function') {
|
|
|
+ onSceneLaunched = parameter;
|
|
|
+ parameter = undefined;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let level = this.sceneStackLevel(sceneName);
|
|
|
+ if(level !== -1){
|
|
|
+ this.goBackToSceneStackLevel(level, parameter);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let readyToLeaveSceneJS = this.getCurrentSceneJS();
|
|
|
+ if(readyToLeaveSceneJS){
|
|
|
+ let sceneKey = 'Scene-' + this._scenesStack.length;
|
|
|
+ let sceneState = this._allState.get(sceneKey);
|
|
|
+ let state = {};
|
|
|
+ sceneState.state = state;
|
|
|
+
|
|
|
+ if(typeof readyToLeaveSceneJS.saveState === 'function'){
|
|
|
+ readyToLeaveSceneJS.saveState.call(readyToLeaveSceneJS, state);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ cc.director.loadScene(sceneName, function () {
|
|
|
+
|
|
|
+ logger.log('navigate loadScene complete sceneName = ' + sceneName);
|
|
|
+
|
|
|
+ this._sceneLaunchHandle = true;
|
|
|
+ this.handleForward(sceneName, parameter);
|
|
|
+
|
|
|
+
|
|
|
+ if(onSceneLaunched){
|
|
|
+ onSceneLaunched();
|
|
|
+ }
|
|
|
+ }.bind(this));
|
|
|
+
|
|
|
+ logger.log('navigate end');
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 向后返回前一个场景
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ */
|
|
|
+ goBack(parameter){
|
|
|
+ logger.log('goBack');
|
|
|
+
|
|
|
+
|
|
|
+ this._scenesStack.pop();
|
|
|
+
|
|
|
+
|
|
|
+ let sceneName = this._scenesStack[this._scenesStack.length - 1];
|
|
|
+ logger.info('goBack to sceneName = ' + sceneName);
|
|
|
+ cc.director.loadScene(sceneName, function () {
|
|
|
+ logger.log('goBack loadScene complete sceneName = ' + sceneName);
|
|
|
+
|
|
|
+ this._sceneLaunchHandle = true;
|
|
|
+ this.handleBack(parameter);
|
|
|
+ }.bind(this));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 向后返回前根场景
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ */
|
|
|
+ goBackToRootScene(parameter){
|
|
|
+ logger.log('goBackToRootScene');
|
|
|
+
|
|
|
+ this.goBackToSceneStackLevel(1, parameter);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 向后返回指定场景
|
|
|
+ * @param {string} sceneName -场景名字
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ */
|
|
|
+ goBackToScene(sceneName, parameter){
|
|
|
+ logger.log('goBackToScene sceneName = ' + sceneName);
|
|
|
+
|
|
|
+ let level = this.sceneStackLevel(sceneName);
|
|
|
+
|
|
|
+ if(level !== -1){
|
|
|
+ this.goBackToSceneStackLevel(level, parameter);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ * 前进页面处理,加入导航栈,分配state
|
|
|
+ * @param {string} sceneName -场景名字
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ */
|
|
|
+ handleForward(sceneName, parameter){
|
|
|
+ logger.info('handleForward sceneName = ' + sceneName);
|
|
|
+ logger.info('handleForward parameter = ' + parameter);
|
|
|
+
|
|
|
+
|
|
|
+ if(sceneName){
|
|
|
+ this._scenesStack.push(sceneName);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let enterSceneJS = this.getCurrentSceneJS();
|
|
|
+ if(enterSceneJS){
|
|
|
+
|
|
|
+ if(typeof enterSceneJS.loadState === 'function'){
|
|
|
+ enterSceneJS.loadState.call(enterSceneJS, navigatorMode.New, parameter, null);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let nextSceneKey = 'Scene-' + this._scenesStack.length;
|
|
|
+ let nextSceneIndex = this._scenesStack.length;
|
|
|
+ while (this._allState.delete(nextSceneKey))
|
|
|
+ {
|
|
|
+ nextSceneIndex ++;
|
|
|
+ nextSceneKey = 'Scene-' + nextSceneIndex;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let sceneState = {};
|
|
|
+ let sceneKey = 'Scene-' + this._scenesStack.length;
|
|
|
+ logger.log('handleForward sceneKey = ' + sceneKey);
|
|
|
+ this._allState.set(sceneKey, sceneState);
|
|
|
+
|
|
|
+
|
|
|
+ parameter = parameter || {};
|
|
|
+ sceneState.parameter = parameter;
|
|
|
+ sceneState.state = {};
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 后退页面处理,恢复场景
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ */
|
|
|
+ handleBack(parameter){
|
|
|
+ logger.info('handleBack');
|
|
|
+
|
|
|
+
|
|
|
+ let enterSceneJS = this.getCurrentSceneJS();
|
|
|
+ if(enterSceneJS){
|
|
|
+ let sceneKey = 'Scene-' + this._scenesStack.length;
|
|
|
+ logger.log('handleBack sceneKey = ' + sceneKey);
|
|
|
+ let sceneState = this._allState.get(sceneKey);
|
|
|
+
|
|
|
+
|
|
|
+ if(typeof enterSceneJS.loadState === 'function'){
|
|
|
+
|
|
|
+ parameter = parameter || sceneState.parameter;
|
|
|
+ enterSceneJS.loadState.call(enterSceneJS, navigatorMode.Back, parameter, sceneState.state);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 刷新页面处理
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ */
|
|
|
+ handleRefresh(parameter){
|
|
|
+ logger.info('handleRefresh');
|
|
|
+
|
|
|
+ let enterSceneJS = this.getCurrentSceneJS();
|
|
|
+ if(enterSceneJS){
|
|
|
+ if(typeof enterSceneJS.loadState === 'function'){
|
|
|
+ enterSceneJS.loadState.call(enterSceneJS, navigatorMode.Refresh, parameter, null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 获取当前场景脚本类
|
|
|
+ */
|
|
|
+ getCurrentSceneJS(){
|
|
|
+ let currentScene = cc.director.getScene();
|
|
|
+ if(currentScene){
|
|
|
+ let currentCanvas = currentScene.getChildByName('Canvas');
|
|
|
+ if(currentCanvas){
|
|
|
+ let currentCustomJS = currentCanvas.getComponent(currentScene.name);
|
|
|
+ if(currentCustomJS){
|
|
|
+ return currentCustomJS;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 返回到固定Level的场景
|
|
|
+ * @param {number} level -层级,比如1代表第一层
|
|
|
+ * @param {object} [parameter] -参数对象
|
|
|
+ */
|
|
|
+ goBackToSceneStackLevel(level, parameter){
|
|
|
+ logger.info('goBackToSceneStackLevel');
|
|
|
+
|
|
|
+ let locScenesStack = this._scenesStack;
|
|
|
+ let c = locScenesStack.length;
|
|
|
+
|
|
|
+ if (c === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (level > c)
|
|
|
+ return;
|
|
|
+
|
|
|
+
|
|
|
+ while (c > level) {
|
|
|
+ let current = locScenesStack.pop();
|
|
|
+ c--;
|
|
|
+ }
|
|
|
+
|
|
|
+ let sceneName = locScenesStack[locScenesStack.length - 1];
|
|
|
+ logger.info('goBackToSceneStackLevel sceneName = ' + sceneName);
|
|
|
+
|
|
|
+ let currentSceneName = cc.director.getScene().name;
|
|
|
+ logger.info('goBackToSceneStackLevel currentSceneName = ' + currentSceneName);
|
|
|
+
|
|
|
+ if(currentSceneName !== sceneName){
|
|
|
+
|
|
|
+ cc.director.loadScene(sceneName, function () {
|
|
|
+ logger.log('goBackToSceneStackLevel loadScene complete sceneName = ' + sceneName);
|
|
|
+
|
|
|
+ this._sceneLaunchHandle = true;
|
|
|
+ this.handleBack(parameter);
|
|
|
+ }.bind(this));
|
|
|
+ }else {
|
|
|
+ this.handleRefresh(parameter);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 获取指定scene名字的导航栈层级
|
|
|
+ * @param {string} sceneName -场景名字
|
|
|
+ */
|
|
|
+ sceneStackLevel(sceneName){
|
|
|
+ logger.log('sceneStackLevel sceneName = ' + sceneName);
|
|
|
+
|
|
|
+ let locScenesStack = this._scenesStack;
|
|
|
+
|
|
|
+ let i = locScenesStack.length-1;
|
|
|
+ let exist = false;
|
|
|
+ for(; i>=0; --i){
|
|
|
+ if(locScenesStack[i] === sceneName){
|
|
|
+ exist = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.log('sceneStackLevel i = ' + i);
|
|
|
+
|
|
|
+ if(exist){
|
|
|
+ return i+1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = {
|
|
|
+
|
|
|
+ * 导航模式
|
|
|
+ */
|
|
|
+ NavigatorMode: navigatorMode,
|
|
|
+
|
|
|
+
|
|
|
+ * get Navigator
|
|
|
+ * @returns {Navigator}
|
|
|
+ */
|
|
|
+ getNavigator: function(){
|
|
|
+ return new Navigator();
|
|
|
+ }
|
|
|
+};
|