@hsui/core
Version:
Hundsun frontend runtime core framework
192 lines (183 loc) • 5.88 kB
JavaScript
import _typeof from "@babel/runtime/helpers/esm/typeof";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import { Model, Router } from '../core';
import { extend, isPlainObject, isUndefined } from '../utils';
import { beforeRouteChange, afterRouteChange } from '../middleware';
import { log } from '../log';
var isNavigationFailure = Router.isNavigationFailure,
NavigationFailureType = Router.NavigationFailureType;
var encodeReserveRE = /[!'()*]/g;
var encodeReserveReplacer = function encodeReserveReplacer(c) {
return '%' + c.charCodeAt(0).toString(16);
};
var commaRE = /%2C/g;
// fixed encodeURIComponent which is more conformant to RFC3986:
// - escapes [!'()*]
// - preserve commas
var encode = function encode(str) {
return encodeURIComponent(str).replace(encodeReserveRE, encodeReserveReplacer).replace(commaRE, ',');
};
var decode = decodeURIComponent;
var defaultRouterOpts = {
scrollBehavior: function scrollBehavior() {
return {
x: 0,
y: 0
};
}
};
var router = null;
export default function initRouter(routes, opts) {
if (router) return router;
// 避免在调用 initRouter 之前注册,在 1.0 的场景下,多个子应用都访问 @hsui/core 的情况下会造成冲突
Model.use(Router);
// 合并 defaultRouterOpts
opts = _objectSpread(_objectSpread({}, defaultRouterOpts), opts);
// 保证在 hash 模式下也能从 location.search 中读取查询参数
// TODO - 暂时还没有解决方案,在主子应用同时存在路由参数的情况下,url 会存在多个 search 片段的问题
if (opts.mode === 'hash') {
opts = _objectSpread(_objectSpread({}, opts), {}, {
parseQuery: function parseQuery(query) {
var res = {};
query = query.trim().replace(/^(\?|#|&)/, '');
if (!query) {
var _location = location,
search = _location.search;
search = search.trim().replace(/^(\?|#|&)/, '');
if (!search) {
return res;
}
query = search;
}
query.split('&').forEach(function (param) {
var parts = param.replace(/\+/g, ' ').split('=');
var key = decode(parts.shift());
var val = parts.length > 0 ? decode(parts.join('=')) : null;
if (res[key] === undefined) {
res[key] = val;
} else if (Array.isArray(res[key])) {
res[key].push(val);
} else {
res[key] = [res[key], val];
}
});
return res;
},
stringifyQuery: function stringifyQuery(obj) {
var res = obj ? Object.keys(obj).map(function (key) {
var val = obj[key];
if (val === undefined) {
return '';
}
if (val === null) {
return encode(key);
}
if (Array.isArray(val)) {
var result = [];
val.forEach(function (val2) {
if (val2 === undefined) {
return;
}
if (val2 === null) {
result.push(encode(key));
} else {
result.push(encode(key) + '=' + encode(val2));
}
});
return result.join('&');
}
return encode(key) + '=' + encode(val);
}).filter(function (x) {
return x.length > 0;
}).join('&') : null;
if (res && !location.search.includes(res)) {
return "?".concat(res);
}
return '';
}
});
}
router = new Router(opts);
if (routes) {
router.addRoutes(routes);
}
log.debug('Router 实例', router);
log.debug('Router 构建选项', opts);
log.debug('Routes 路由记录', router.getRoutes());
router.beforeEach(function (to, from, next) {
log.debug('路由跳转前置导航守卫', to, from);
next();
});
beforeRouteChange.middlewares.forEach(function (middleware) {
return router.beforeEach(middleware);
});
router.afterEach(function (to, from) {
log.debug('路由跳转后置导航守卫', to, from);
afterRouteChange.justRun(to, from);
});
return router;
}
/**
* Set default router options
* @param {object} opts
*/
export function setRouterOpts(opts) {
extend(defaultRouterOpts, opts);
}
/**
* @description jump programmatically
* @param {String} path target path
* @param {Object} opts options
* @param {Boolean} opts.history whether to keep current browser history, perform like pushState or replaceState, default true
* @param {Boolean} opts.animation todo
* @param {Object} query query params
*/
export function navigate(path, opts, query) {
if (!router) return;
var defaultOpts = {
history: true
};
var defaultQuery = {};
if (!_typeof(path) === 'string' || path === '') {
log.error('navigate 方法必须指定 path 为字符串类型且不能为空');
return false;
}
// 只有两个参数,则第二个为 query
if (isPlainObject(opts) && isUndefined(query)) {
query = opts;
opts = defaultOpts;
}
// path 是必填项
if (isUndefined(opts)) {
opts = defaultOpts;
query = defaultQuery;
}
var _opts = opts,
history = _opts.history;
var onError = function onError(err) {
if (isNavigationFailure(err, NavigationFailureType.duplicated) || isNavigationFailure(err, NavigationFailureType.redirected)) {
return;
}
log.error('路由跳转异常', err);
throw err;
};
if (history) {
router.push({
path: path,
query: query
}).catch(onError);
} else {
router.replace({
path: path,
query: query
}).catch(onError);
}
}
/**
* @description go forwards or go backwards in the history stack programmatically
* @param {Number} n steps to go, setting to 0 perform like reload
*/
export function go(n) {
if (!router) return;
router.go(n);
}