UNPKG

cyra

Version:

single page application view engine

268 lines (267 loc) 9.38 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var history_1 = require("./she/history"); var hash_1 = require("./she/hash"); var multipage_1 = require("./she/multipage"); var Route_1 = require("./Route"); var Storage_1 = require("./Storage"); var MODE_HISTORY = 'history'; var MODE_HASH = 'hash'; var MODE_MULTIPAGE = 'multipage'; var KEY_CR_POP = '_CR_POP_SWITCH'; var CYRA_HOOK = '__CYRA_DEVTOOLS_GLOBAL_HOOK__'; var Router = (function () { function Router(root, defaultPath, mode) { this.models = { pages: {}, routes: [], }; this.context = {}; // 用来指示是否需要 switchPage this.isPoping = false; this.mode = mode; this.defaultPath = defaultPath; this.context.rootContainer = document.querySelector(root); this.context.data = {}; Storage_1.AppStorage.init(); this.initRouter(); this.initHook(); } /** * 通过 path 获取 Route * @param {string} path * @return {Route} */ Router.prototype.getRouteByPath = function (path) { var routes = this.models.routes; for (var i = 0, length_1 = routes.length; i < length_1; i++) { if (routes[i].path === path) { return routes[i]; } } }; /** * 通过 path 获取 Page * @param {string} path * @param {number} copyIndex * @return {Page} */ Router.prototype.getPageByPath = function (path, copyIndex) { var pages = this.models.pages[path]; copyIndex = copyIndex || 0; if (!pages) { throw new Error('Route Path 错误'); } var page = pages.instances[copyIndex]; if (!page) { page = new pages.pageClass(path); page.copyIndex = copyIndex; pages.instances[copyIndex] = page; } return page; }; /** * 定义路由 * @param {RouteData} routes * @return {Array<Route>} */ Router.prototype.defineRoute = function (routes) { for (var path in routes) { var PageClass = routes[path]; var page = new PageClass(path); this.models.pages[path] = { pageClass: PageClass, instances: [page], }; var route = new Route_1.Route(path, page); this.models.routes.push(route); } window[CYRA_HOOK].emit('init_routes', this.models.routes); return this.models.routes; }; /** * 初始化 Router */ Router.prototype.initRouter = function () { var _this = this; var routing = function (getParams) { var urlObject = getParams(); /** * popAndSwitchRoute 会 pop 历史记录,不需要路由 */ if (_this.isPoping) { _this.isPoping = false; return; } var path = urlObject.path || _this.defaultPath; var matchedRoute = _this.getRouteByPath(path); if (matchedRoute) { window[CYRA_HOOK].emit('switch_route', { path: path, useSwitch: _this.context.useSwitch, data: urlObject.data, }); _this.beforeSwitchPage(matchedRoute, urlObject); // 把状态改变放在了 Page 模块中的 entering 钩子中 // this.context.useSwitch = false; } else { throw new Error('Route Path 错误'); } }; var pathParams = { routing: routing }; if (this.mode === MODE_HISTORY) { this.pathHandler = new history_1.default(pathParams); } else if (this.mode === MODE_HASH) { this.pathHandler = new hash_1.default(pathParams); } else { this.pathHandler = new multipage_1.default(pathParams); } }; /** * 开始路由 */ Router.prototype.startRouting = function () { this.pathHandler.start(); }; /** * 更新 URL * @param {string} path * @param {number} copyIndex * @param {any} data */ Router.prototype.updatePath = function (path, title, copyIndex, data, isShadow) { var urlObject = { path: path, title: title, data: data, copyIndex: copyIndex, }; this.pathHandler.updatePath(urlObject, isShadow); }; /** * 模拟拦截用户点击返回按钮 */ Router.prototype.cancelBack = function () { window.history.forward(); this.isPoping = true; }; /** * 在 switchPage 之前执行,提供拦截方式 * @param {Route} matchedRoute * @param {UrlObject} urlObject */ Router.prototype.beforeSwitchPage = function (matchedRoute, urlObject) { if (this.context.currentRoute) { var currentPage = this.context.currentPage; var next = this.switchPage.bind(this, matchedRoute, urlObject); currentPage.beforeLeaving(next, this.cancelBack.bind(this), urlObject.path); } else { this.switchPage(matchedRoute, urlObject); } }; /** * 切换页面,设置 context * @param {Route} matchedRoute * @param {UrlObject} urlObject */ Router.prototype.switchPage = function (matchedRoute, urlObject) { var _this = this; if (this.context.currentRoute) { this.context.previousPage = this.context.currentPage; this.context.currentPage.leaving(); } this.context.currentRoute = matchedRoute; // 多页 popAndSwitchRoute 操作 pop 之后执行 switchRoute if (this.mode === MODE_MULTIPAGE) { var popSwitchState_1 = Storage_1.AppStorage.get(KEY_CR_POP); if (popSwitchState_1 && popSwitchState_1.path) { Storage_1.AppStorage.clear(KEY_CR_POP); Storage_1.AppStorage.save(); // 不同浏览器/WebView有bug,如果时间过短则不会在Session History中保留该条记录 setTimeout(function () { _this.pathHandler.updatePath(popSwitchState_1, false); }, 200); return; } } var matchedPage = this.getPageByPath(matchedRoute.path, urlObject.copyIndex); this.context.currentPage = matchedPage; matchedPage.entering(urlObject.data, urlObject.copyIndex); // 多页方案进入页面时模拟执行上个页面的 destinationSwitch if (this.mode === MODE_MULTIPAGE) { var methods = Storage_1.AppStorage.getDestinationMethods(); for (var i = 0; i < methods.length; i++) { matchedPage.multiCallMethods.apply(matchedPage, [methods[i].funcName].concat(methods[i].args)); } Storage_1.AppStorage.clearMethodsQueue(); } }; /** * Page 执行跳转 * @param {string} path * @param {any} data */ Router.prototype.switchRoute = function (path, data, copyIndex, isShadow) { if (isShadow === void 0) { isShadow = false; } if (!copyIndex && typeof copyIndex !== 'number') { var currCopyIndex = this.context.currentPage.copyIndex || 0; copyIndex = (path === this.context.currentPage.path) ? (currCopyIndex + 1) : 0; } var destinationPage = this.getPageByPath(path, copyIndex); if (destinationPage) { this.context.useSwitch = true; var title = this.context.currentPage.title(); var updatePath = this.updatePath.bind(this, path, title, copyIndex, data, isShadow); var destinationPagePerform = destinationPage.callMethods.bind(destinationPage); this.context.previousPage = this.context.currentPage; this.context.currentPage.prepareForSwitch(updatePath, path, destinationPagePerform); } else { throw new Error('Route Path 错误'); } }; /** * Page pop 页面然后执行跳转 * @param {number} popValue * @param {string} path * @param {any} data */ Router.prototype.popAndSwitchRoute = function (popValue, path, data, copyIndex) { var _this = this; if (this.mode === MODE_MULTIPAGE) { Storage_1.AppStorage.set(KEY_CR_POP, { path: path, data: data, copyIndex: copyIndex, }); Storage_1.AppStorage.save(); window.history.go(-popValue); return; } if (popValue) { window.history.go(-popValue); this.isPoping = true; } // 为兼容Android添加100ms延迟 setTimeout(function () { _this.switchRoute(path, data, copyIndex); }, 100); }; /** * 设置默认插件辅助方法 */ Router.prototype.initHook = function () { if (!window[CYRA_HOOK]) { window[CYRA_HOOK] = { on: function () { }, emit: function (type, data) { }, }; } }; return Router; }()); exports.default = Router;