UNPKG

@gem-mine/durex-router

Version:

router for @gem-mine/durex

554 lines (454 loc) 16.6 kB
'use strict'; 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]; } };