@gem-mine/durex-router
Version:
router for @gem-mine/durex
554 lines (454 loc) • 16.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.router = exports.Routes = undefined;
var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
var _iterator = require('babel-runtime/core-js/symbol/iterator');
var _iterator2 = _interopRequireDefault(_iterator);
var _symbol = require('babel-runtime/core-js/symbol');
var _symbol2 = _interopRequireDefault(_symbol);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _defineProperty2 = require('babel-runtime/core-js/object/define-property');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _setPrototypeOf = require('babel-runtime/core-js/object/set-prototype-of');
var _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf);
var _create = require('babel-runtime/core-js/object/create');
var _create2 = _interopRequireDefault(_create);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; (0, _defineProperty3.default)(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _extends = _assign2.default || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof _symbol2.default === "function" && typeof _iterator2.default === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj; };
exports.getQuery = getQuery;
exports.urlFor = urlFor;
exports.getRouteByKeyPath = getRouteByKeyPath;
exports.getRouteByUrlPath = getRouteByUrlPath;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactRouter = require('react-router');
var _pathToRegexp = require('path-to-regexp');
var _pathToRegexp2 = _interopRequireDefault(_pathToRegexp);
var _queryString = require('query-string');
var _queryString2 = _interopRequireDefault(_queryString);
var _router = require('./router');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new _promise2.default(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return _promise2.default.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass; }
function _defineProperty(obj, key, value) { if (key in obj) { (0, _defineProperty3.default)(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var ROOT = '__root__';
// 缓存拍扁的路由信息,key 是 keyPath,value 是 路由JSON配置
// 可以通过此缓存根据 keyPath查询到对应的路由(getRouteByKeyPath)
var _routers = {};
// 缓存拍扁的子路由,key 是 keyPath, value 是所有子路由数组
var _sub = _defineProperty({}, ROOT, []);
// 缓存,key 是 url 路径(/user/profile),value 是 路由JSON配置
// 用来检测该路径是否被注册,如果重复注册,用来警告
// 同时可以通过此缓存根据路径查询到对应的路由(getRouteByUrlPath)
var _cache = {};
// 缓存 config
var _config = {
components: {
NotFound: function NotFound(props) {
return _react2.default.createElement(
'div',
null,
'404 not found'
);
},
Forbidden: function Forbidden(props) {
return _react2.default.createElement(
'div',
null,
'403 forbidden'
);
},
Loading: function Loading(props) {
return _react2.default.createElement(
'div',
null,
'loading...'
);
}
}
};
function getQuery(url) {
var query = url.split('?')[1];
if (query) {
if (query.indexOf('#') > -1) {
query = query.split(/\/?#/)[0];
}
query = _queryString2.default.parse(query);
return query;
}
return {};
}
function parseRedirect(_ref) {
var from = _ref.from,
to = _ref.to;
var query = getQuery(location.href);
if (typeof to === 'function') {
to = to({ from: from, to: to });
}
if (to) {
if ((typeof to === 'undefined' ? 'undefined' : _typeof(to)) === 'object') {
if (typeof to.params === 'function') {
_extends(query, to.params(query));
} else {
_extends(query, to.params);
}
to = urlFor(to.key);
} else {
var t = _routers[to];
if (t) {
to = t.path;
} else {
console.warn('route ' + to + ' not exist, redirect fail, please check route config');
}
}
if (to) {
return _react2.default.createElement(_reactRouter.Redirect, { exact: true, from: from, to: {
pathname: to,
search: _queryString2.default.stringify(_extends({}, query))
}, key: to });
}
}
}
function _parseRedirect(route) {
var to = route.redirect;
// 有子路由的不处理 redirect,防止是跳转进入子路由引起死循环
if (!route.sub && to) {
return parseRedirect({
from: route.path,
to: to
});
}
}
/**
* 添加一个路由
*/
function add(parent, items) {
var keyPath = '';
var pathPrefix = '';
if (parent) {
if (parent.keyPath) {
keyPath = parent.keyPath + '.' + parent.key;
} else {
keyPath = parent.key;
}
if (parent.path && parent.path !== '/') {
pathPrefix = parent.path;
}
}
(0, _keys2.default)(items).forEach(function (key) {
var item = items[key];
item.key = key;
item.keyPath = keyPath;
if (!item.path && item.component) {
item.exact = true;
}
item.path = ('' + pathPrefix + (item.path || '')).replace(/\/\/|\/$/g, '') || '/';
var subKey = ROOT;
if (parent) {
item.parent = parent;
var kp = getParentKeyPath(keyPath);
// 祖先存在是子路由, 应往最近的具有子路由的祖先中添加
if (kp) {
subKey = kp;
}
}
_sub[subKey].push(item);
var selfPath = keyPath ? keyPath + '.' + item.key : item.key;
_routers[selfPath] = item;
if (item.index) {
var target = _extends({}, item);
delete target.index;
if (item.component) {
target.path = pathPrefix || '/';
target.exact = true;
} else if (item.redirect) {
target = {
key: item.parent.key,
path: item.parent.path,
redirect: item.redirect
};
}
_sub[subKey].push(target);
}
// 具有子路由
if (item.sub) {
_sub[selfPath] = [];
add(item, item.sub);
}
// 具有子模块
if (item.module) {
add(item, item.module);
}
if (item.component) {
if (_cache[item.path]) {
// 路由容器不参与去重判定,因为其子节点会可能存在默认路由,其路径和路由容器一致
if (!item.sub) {
console.warn(item.path + ' \u5DF2\u7ECF\u88AB\u6CE8\u518C\uFF0C\u751F\u6548\u7684\u662F\u9996\u4E2A\u6CE8\u518C\u7684\u7EC4\u4EF6\uFF1A', _cache[item.path], '\u5F53\u524D\u7EC4\u4EF6\u4E0D\u751F\u6548\uFF1A', item);
}
} else {
_cache[item.path] = item;
}
}
});
}
function getParentKeyPath(keyPath) {
var arr = keyPath.split('.');
var i = arr.length;
var p = void 0;
while (i >= 0) {
var key = arr.slice(0, i).join('.');
p = _sub[key];
if (p) {
return key;
}
i -= 1;
}
return false;
}
var Permission = function (_React$Component) {
_inherits(Permission, _React$Component);
function Permission(props) {
_classCallCheck(this, Permission);
var _this = _possibleConstructorReturn(this, (Permission.__proto__ || (0, _getPrototypeOf2.default)(Permission)).call(this, props));
_this.state = {};
return _this;
}
_createClass(Permission, [{
key: 'componentDidMount',
value: function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regenerator2.default.mark(function _callee() {
var p, arr, flag, i;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
p = this.props;
arr = [];
while (p) {
if (typeof p.permission === 'function') {
arr.push(p.permission);
}
p = p.parent;
}
this.setState({
loading: true
});
flag = true;
i = 0;
case 6:
if (!(i < arr.length)) {
_context.next = 15;
break;
}
_context.next = 9;
return arr[i](this.props);
case 9:
flag = _context.sent;
if (!(flag !== true)) {
_context.next = 12;
break;
}
return _context.abrupt('break', 15);
case 12:
i++;
_context.next = 6;
break;
case 15:
this.setState({
flag: flag,
loading: false
});
case 16:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
function componentDidMount() {
return _ref2.apply(this, arguments);
}
return componentDidMount;
}()
}, {
key: 'render',
value: function render() {
var _props = this.props,
Component = _props.component,
permission = _props.permission,
rest = _objectWithoutProperties(_props, ['component', 'permission']); // eslint-disable-line
var _state = this.state,
flag = _state.flag,
loading = _state.loading;
return _react2.default.createElement(_reactRouter.Route, _extends({}, rest, {
render: function render(props) {
if (loading) {
return _react2.default.createElement(_config.components.Loading, props);
} else {
if (flag === true) {
// 合法
return _react2.default.createElement(Component, props);
} else {
// 不合法
if (flag) {
// 验证函数返回Component,直接显示
return flag;
}
return _react2.default.createElement(_config.components.Forbidden, props);
}
}
}
}));
}
}]);
return Permission;
}(_react2.default.Component);
/**
* 解析 url
* @param {String} key,对应路由定义中的 key
* @param {Object} params 参数列表,url中有的替换,没有的作为查询参数
*/
function urlFor(key, params) {
var router = _routers[key];
if (!router) {
console.warn('router: ' + key + ' not register');
return '';
}
var path = router.path;
if (!params) {
return path;
}
var keys = [];
(0, _pathToRegexp2.default)(path, keys);
var url = path;
var temp = {};
keys.forEach(function (item) {
var name = item.name,
prefix = item.prefix;
if (params.hasOwnProperty(name)) {
url = url.replace(new RegExp(prefix + '(:' + name + ')\\/?', 'g'), function (str, match) {
return str.replace(match, params[name]);
});
temp[name] = true;
} else {
console.error(path + ': ' + name + ' missing value');
}
});
var obj = {};
(0, _keys2.default)(params).forEach(function (key) {
if (!temp.hasOwnProperty(key)) {
obj[key] = params[key];
}
});
var c = url.indexOf('?') > -1 ? '&' : '?';
url = '' + url + c + _queryString2.default.stringify(obj);
return url;
}
var Routes = exports.Routes = function Routes(props) {
var path = props.path,
children = props.children;
var rs = void 0;
if (path) {
rs = _sub[path];
} else {
rs = _sub.__root__;
}
if (rs && rs.length) {
var routes = [];
var redirects = [];
rs.forEach(function (route) {
if (route) {
var redirect = void 0;
if (route.redirect) {
redirect = _parseRedirect(route);
}
if (redirect) {
redirects.push(redirect);
} else if (route.component) {
routes.push(_react2.default.createElement(Permission, _extends({}, route, { key: route.key })));
}
}
});
return _react2.default.createElement(
_reactRouter.Switch,
null,
redirects,
routes,
children,
_react2.default.createElement(_reactRouter.Route, { component: _config.components.NotFound })
);
}
};
/**
* 根据 key path 获取对应的路由对象,getRouteByKeyPath('main.home')
* @param {string} keyPath
*/
function getRouteByKeyPath(keyPath) {
return _routers[keyPath];
}
/**
* 根据 url path 获取对应的路由对象,getRouteByUrlPath('/user/home/setting')
* @param {string} urlPath
*/
function getRouteByUrlPath(urlPath) {
var route = _cache[urlPath];
if (route) {
return route;
}
(0, _keys2.default)(_cache).some(function (key) {
var item = _cache[key];
var re = (0, _pathToRegexp2.default)(item.path);
if (re.test(urlPath)) {
route = item;
}
});
return route;
}
var router = exports.router = {
// 配置
config: function config() {
var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
mode = _ref3.mode,
history = _ref3.history,
components = _ref3.components;
if (mode || history) {
(0, _router.createHistory)(mode || history);
}
if (components) {
_extends(_config.components, components);
}
},
// 路由统一注册入口
register: function register(keyPath, items, isSub) {
if ((typeof keyPath === 'undefined' ? 'undefined' : _typeof(keyPath)) === 'object') {
items = keyPath;
keyPath = '';
}
var parent = _routers[keyPath];
add(parent, items);
},
Routes: Routes,
getFlat: function getFlat() {
return _routers;
},
getSub: function getSub(key) {
if (!key) {
key = ROOT;
}
return _sub[key];
}
};