cyra
Version:
single page application view engine
268 lines (267 loc) • 9.38 kB
JavaScript
"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;