react-router源码

前端之家收集整理的这篇文章主要介绍了react-router源码前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

1.Router.js

Router.js模块用于监听hashChange、popState事件,通过当前页面url更新Router组件的state,state形式为{location,routes,params,components},其中location为当前页面的路径数据,routes为当前页面路径下被激活的Route、IndexRoute、Redirect、IndexRedirect元素,params为当前页面的路径数据变量,components为当前页面下待渲染的UI组件。

UI组件借由RouterContent.js模块完成,通过在Router组件的render方法调用React.createElement(RouterContent,props)实现渲染。Router的state数据{location,components}将作为RouterContent组件的props,因此路径变更时将引起RouterContent组件的props变更,而props的变更又将引起RouterContent组件的重绘。

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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; }; // node模块;invariant(condition,format,a,b,c,d,e,f),condition为否值时,以a,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); var _react = require('react'); var _react2 = _interoprequiredefault(_react); // 创建transitionManager对象,用于监听、取消监听popstate、hashChange事件 var _createTransitionManager2 = require('./createTransitionManager'); var _createTransitionManager3 = _interoprequiredefault(_createTransitionManager2); // props属性校验 var _InternalPropTypes = require('./InternalPropTypes'); // 负责渲染Router下子Route挂载的组件,由Router的state数据获取到激活的Route组件及其components待挂载的组件 // 通过底层的Route组件向上遍历父Route,创建待挂载渲染的props.component|components组件元素reactElement实现 var _RouterContext = require('./RouterContext'); var _RouterContext2 = _interoprequiredefault(_RouterContext); // 提供一系列方法,目的是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 var _RouteUtils = require('./RouteUtils'); // 提供createRouterObject、assignRouterState方法 // createRouterObject(history,transitionManager,state)方法 // 创建复合对象,含有histroy绑定路由事件、获取路由数据、跳转路由相关方法 // 以及setRouteLeaveHook、isActive方法 // 及location、params、routes属性(同Router组件当前state的相关属性等值) // assignRouterState(router,_ref)拷贝_ref的location、params、routes属性给router // 次参_ref通常是Router组件当前的state var _RouterUtils = require('./RouterUtils'); // 封装warning模块,目的是使含'deprecated'的警告文案只提示一次 var _routerWarning = require('./routerWarning'); var _routerWarning2 = _interoprequiredefault(_routerWarning); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // obj的属性方法在keys中也有,不予拷贝 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; }; var _React$PropTypes = _react2.default.PropTypes,func = _React$PropTypes.func,object = _React$PropTypes.object; // var props={ // history,// hashHistory、broswerHistroy、memoryHistory内含绑定路由事件、获取路由数据、跳转路由相关方法 // onError,// 页面跳转发生错误时,捕获错误并处理,设置时默认不报错 // onUpdate,// 页面跳转成功、组件重绘后,调用onUpdate方法 // children,// 子Route组件 // routes,// 同children等同,页面路由Route组件设置 // render,// 决定Route中components组件渲染机制,默认调用react.createElement // createElement,// 负责Route下待挂载组件的渲染createElement(component,props); // matchContext??? // } // <Router {...props}><Route/><Router/> // Router通过props.render方法调用RouterContent模块访问props.children即Route组件渲染Route.components组件 // <Router {...props}><Route/><Router/>书写方式Route组件不渲染的根由??? // Router模块内部通过createTransitionManager模块创建this.transitionManager对象用于管理路由事件 // 路由事件触发时,更新state={routes,location,component}形式,重新渲染组件 // 通过RouterUtils模块创建this.router对象用于管理路由事件、访问路由数据,向下传递给RouterContent渲染模块用 var Router = _react2.default.createClass({ displayName: 'Router',propTypes: { history: object,// hashHistory、broswerHistroy、memoryHistory内含绑定路由事件、获取路由数据、跳转路由相关方法 children: _InternalPropTypes.routes,// 子Route组件 routes: _InternalPropTypes.routes,// 同props.children,子Route组件 render: func,// Route中components组件渲染机制,render({router,components,createElement,props}) // props含有部分Router组件接收到的props createElement: func,props); onError: func,// 报错时执行函数 onUpdate: func,// 路径变更时执行函数 // PRIVATE: For client-side rehydration of server match.??? matchContext: object },// 添加this.props.render方法 getDefaultProps: function getDefaultProps() { return { render: function render(props) { return _react2.default.createElement(_RouterContext2.default,props); } }; },getInitialState: function getInitialState() { // 路径改变时赋值location路径数据、routes激活的Route、params路径变量数据、components挂载的组件 // 通过componentWillMount方法调用this.transitionManager.listen实现 return { location: null,routes: null,params: null,components: null }; },// 错误处理 handleError: function handleError(error) { if (this.props.onError) { this.props.onError.call(this,error); } else { throw error; } },// 创建对象,内含绑定路由事件、获取路由数据、跳转路由、判断路径是否激活相关方法 // location、params、routes属性访问当前state的数据 createRouterObject: function createRouterObject(state) { var matchContext = this.props.matchContext; if (matchContext) { return matchContext.router; } // props.history为hashHistory、broswerHistroy、memoryHistory内含绑定路由事件、获取路由数据、跳转路由相关方法 var history = this.props.history; // _RouterUtils.createRouterObject方法用于创建复合对象,含有histroy绑定路由事件、获取路由数据、跳转路由相关方法 // 以及setRouteLeaveHook、isActive方法 // 及location、params、routes属性(同Router组件当前state的相关属性等值) return (0,_RouterUtils.createRouterObject)(history,this.transitionManager,state); },// 创建transitionManager对象,用于监听、取消监听popstate、hashChange事件 createTransitionManager: function createTransitionManager() { var matchContext = this.props.matchContext; if (matchContext) { return matchContext.transitionManager; } var history = this.props.history;// hashHistory、broswerHistroy、memoryHistory var _props = this.props,routes = _props.routes,// 路由设置规则<route path="" component=""> children = _props.children;// 路由设置规则<route path="" component=""> !history.getCurrentLocation ? process.env.NODE_ENV !== 'production' ? (0,_invariant2.default)(false,'You have provided a history object created with history v2.x or ' + 'earlier. This version of React Router is only compatible with v3 ' + 'history objects. Please upgrade to history v3.x.') : (0,_invariant2.default)(false) : void 0; return (0,_createTransitionManager3.default)(history,(0,_RouteUtils.createRoutes)(routes || children)); },// 创建transitionManager对象用于绑定事件,router对象用于操作路由、访问当前路由状况 // 绑定事件,哈希路径改变时更新router对象数据、更新组件、触发props.onUpdate回调 componentWillMount: function componentWillMount() { var _this = this; // 创建transitionManager对象,用于监听、取消监听popstate、hashChange事件 this.transitionManager = this.createTransitionManager(); // 创建对象,内含绑定路由事件、获取路由数据、跳转路由、判断路径是否激活相关方法 // location、params、routes属性访问当前state的数据 this.router = this.createRouterObject(this.state); // 哈希路径变更时,触发histroy回调 // 通过回调触发Router组件的更新router对象数据、更新setState,以及props.onUpdate函数的执行 // 获取获取state信息为{routes,component}形式,执行回调 // 并触发Route组件配置的route.onChange|onEnter|onLeave方法执行 this._unlisten = this.transitionManager.listen(function (error,state) { if (error) { _this.handleError(error); } else { // 更新this.router中的location、params、routes数据,指向state即当前页面路径相关数据 (0,_RouterUtils.assignRouterState)(_this.router,state); _this.setState(state,_this.props.onUpdate); } }); },// 提示不能重设props.histroy|routes|children componentWillReceiveProps: function componentWillReceiveProps(nextProps) { process.env.NODE_ENV !== 'production' ? (0,_routerWarning2.default)(nextProps.history === this.props.history,'You cannot change <Router history>; it will be ignored') : void 0; process.env.NODE_ENV !== 'production' ? (0,_routerWarning2.default)( (nextProps.routes || nextProps.children) === (this.props.routes || this.props.children),'You cannot change <Router routes>; it will be ignored' ) : void 0; },// 解绑事件 componentWillUnmount: function componentWillUnmount() { if (this._unlisten) this._unlisten(); },render: function render() { var _state = this.state,location = _state.location,routes = _state.routes,params = _state.params,components = _state.components; var _props2 = this.props,createElement = _props2.createElement,render = _props2.render,props = _objectWithoutProperties(_props2,['createElement','render']); if (location == null) return null; // Async match // Router.props部分属性方法不拷贝给RouterContent渲染模块 Object.keys(Router.propTypes).forEach(function (propType) { return delete props[propType]; }); // 调用props.render创建reactElement元素 return render(_extends({},props,{ router: this.router,location: location,routes: routes,params: params,components: components,createElement: createElement })); } }); exports.default = Router; module.exports = exports['default'];

2.createTransitionManager.js

Router.js模块中调用,用于创建this.transition对象绑点事件,Router.js模块中直接调用this.transition.listen方法监听hashChange、popstate事件,更新Router组件的state={location,components},引起RouterContent组件的props变更,进而实现RouterContent组件重绘,渲染当前路径下待挂载的components组件。

this.transition含有isActive、listenBeforeLeavingRoute、match、listen四个方法

isActive(location,indexOnly) 该方法同时会挂载到Router组件的this.router.isActive方法上,因此使用withRouter(WrapComponent)封装的WrapComponent组件通过this.content.router.isActive可以访问该接口。该方法的意义是判断location路径数据同当前页面的路径数据是否匹配:indexOnly为真时,通过路径数据location解析到的pathname需要与当前页面的pathname严格相等,这在react-router内部判断IndexLink组件路径是否匹配当前页面路径时使用;indexOnly为否时,通过当前激活的routes判断location路径数据是否匹配当前页面路径背后由Route元素设定的路由规则。

listenBeforeLeavingRoute(route,hook)该方法同时会挂载到Router组件的this.router.setRouteLeaveHook方法上,因此使用withRouter(WrapComponent)封装的WrapComponent组件通过this.content.router.setRouteLeaveHook可以访问该接口。当页面离开route时,将执行hook函数,返回否值阻止页面跳转;字符串值将弹出警告窗口,这在react-route的依赖history模块中实现。

match(location,callback) 该方法只在react-route内部使用,即Router.js模块内通过this.transition.listen监听hashChange、popstate事件绑点函数时将调用,传入的首参location为待变更的路径数据,次参callback变更Router组件的state={location,components},并引起RouterContent组件重绘。传入首参location的实质性意义是通过待变更路径数据获取路径数据变量params、即将激活的routes元素(包括Route、IndexRoute、Redirect、IndexRedirect元素),由routes元素获取待挂载的组件components,最终获得待更待state={location,components}数据或者Redirect、IndexRedirect元素激活时的重定向地址redirectLocation,实现页面跳转或更新Router元素的state。

listen(listener)该方法只在react-route内部使用,即Router.js模块中调用,意义是监听hashChange、popstate事件,通过当前页面路径数据获取更迭后的state={location,components}或重定向路径数据redirectLocation,触发Router组件setState方法,重绘RouterContent组件。

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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; }; exports.default = createTransitionManager; // 封装warning模块,目的是使含'deprecated'的警告文案只提示一次 var _routerWarning = require('./routerWarning'); var _routerWarning2 = _interoprequiredefault(_routerWarning); // computeChangedRoutes(prevState,nextState),state.routes是Route组件的配置,数组形式 // 获取prevState待改变的route项leaveRoutes,nextState中保持与prevState相同的route项changeRoutes // nextState中与prevState相同的route项changeRoutes,或者route.path改变,或者state.params改变 var _computeChangedRoutes2 = require('./computeChangedRoutes'); var _computeChangedRoutes3 = _interoprequiredefault(_computeChangedRoutes2); // 通过runChangeHooks|runEnterHooks|runLeaveHooks间接执行route.onChange|onEnter|onLeave方法 var _TransitionUtils = require('./TransitionUtils'); // isActive(_ref,indexOnly,currentLocation,params)判断路径数据_ref同当前路径是否相同 // 参数_ref待校验的路径数据location // indexOnly为真值时路径pathname需要完全匹配,否则pathname匹配激活的route设下的路由规则即可 // 参数currentLocation,params当前页面相关数据 var _isActive2 = require('./isActive'); var _isActive3 = _interoprequiredefault(_isActive2); // getComponents(nextState,callback)获取激活路径下挂载的多个组件,并执行回调 var _getComponents = require('./getComponents'); var _getComponents2 = _interoprequiredefault(_getComponents); // matchRoutes(routes,callback)获取当前路径下被激活的Route组件以及路径变量信息params,{routes,params}形式 // 并且将{routes,params}传入回调callback函数作为参数,routes中含有indexRoute元素的配置信息已获取待加载的组件 var _matchRoutes = require('./matchRoutes'); var _matchRoutes2 = _interoprequiredefault(_matchRoutes); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // 判断object对象有否自有属性 function hasAnyProperties(object) { for (var p in object) { if (Object.prototype.hasOwnProperty.call(object,p)) return true; } return false; } // 创建transitionManager对象,用于监听、取消监听popstate、hashChange事件 // 参数history为hashHistory、broswerHistroy、memoryHistory中的一种 // 参数routes为Router元素下挂载的子元素this.props.children或this.props.routes function createTransitionManager(history,routes) { var state = {}; // isActive(location,indexOnly)判断location同当前路径是否相同 // indexOnly为真值时路径pathname需要完全匹配,否则pathname匹配激活的route设下的路由规则即可 function isActive(location,indexOnly) { // 创建location数据对象 location = history.createLocation(location); // isActive(_ref,params)判断路径数据_ref同当前路径是否相同 // 参数_ref待校验的路径数据location // indexOnly为真值时路径pathname需要完全匹配,否则pathname匹配激活的route设下的路由规则即可 // 参数currentLocation,params当前页面相关数据 return (0,_isActive3.default)(location,state.location,state.routes,state.params); } var partialNextState = void 0; // 参数location变更后的路径数据 // 获取激活的Route信息、待挂载的组件信息、路径变量信息(即state数据信息) // state以{routes,component}形式传入callback中,并执行callback // 期间触发Route组件配置的route.onChange|onEnter|onLeave方法执行 function match(location,callback) { if (partialNextState && partialNextState.location === location) { // Continue from where we left off. finishMatch(partialNextState,callback); } else { // matchRoutes(routes,params}形式 // 并且将{routes,params}传入回调callback函数作为参数 (0,_matchRoutes2.default)(routes,function (error,nextState) { if (error) { callback(error); } else if (nextState) { finishMatch(_extends({},nextState,{ location: location }),callback); } else { callback(); } }); } } // 参数nextState由match函数传入,{routes,location}形式 // 触发route.onChange|onEnter|onLeave方法执行 function finishMatch(nextState,callback) { // computeChangedRoutes(prevState,nextState),state.routes是Route组件的配置,数组形式 // 获取prevState待改变的route项leaveRoutes,nextState中保持与prevState相同的route项changeRoutes // nextState中与prevState相同的route项changeRoutes,或者route.path改变,或者state.params改变 var _computeChangedRoutes = (0,_computeChangedRoutes3.default)(state,nextState),leaveRoutes = _computeChangedRoutes.leaveRoutes,changeRoutes = _computeChangedRoutes.changeRoutes,enterRoutes = _computeChangedRoutes.enterRoutes; // 间接执行Route及IndexRoute及Redirect组件上用户设置的onLeave方法 (0,_TransitionUtils.runLeaveHooks)(leaveRoutes,state); // Tear down confirmation hooks for left routes ??? leaveRoutes.filter(function (route) { return enterRoutes.indexOf(route) === -1; }).forEach(removeListenBeforeHooksForRoute); // 间接执行Route及IndexRoute及Redirect组件上用户设置的onChange方法 (0,_TransitionUtils.runChangeHooks)(changeRoutes,state,redirectInfo) { if (error || redirectInfo) return handleErrorOrRedirect(error,redirectInfo); // 间接执行Route及IndexRoute及Redirect组件上用户设置的onEnter方法 // Redirect元素被激活时,将触发该元素的onEnter方法重定向页面路径 (0,_TransitionUtils.runEnterHooks)(enterRoutes,finishEnterHooks); }); function finishEnterHooks(error,redirectInfo); // getComponents(nextState,callback)获取激活路径下挂载的多个组件,并执行回调 (0,_getComponents2.default)(nextState,components) { if (error) { callback(error); } else { // callback执行参数state为{routes,location}形式 callback(null,null,state = _extends({},{ components: components })); } }); } function handleErrorOrRedirect(error,redirectInfo) { if (error) callback(error);else callback(null,redirectInfo); } } var RouteGuid = 1; // route有__id__属性,返回该属性;否则次参为真值时,以RouteGuid创建__id__属性后返回 function getRouteID(route) { var create = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; return route.__id__ || create && (route.__id__ = RouteGuid++); } var RouteHooks = Object.create(null); // 获取用户调用transitionManager.listenBeforeLeavingRoute(route,hook)添加的前置钩子执行函数 // transitionManager.listenBeforeLeavingRoute在Router模块中可通过this.transition调用 // 在使用withRouter(WrappedComponent)封装的WrappedComponent模块中可通过this.props.router.setRouteLeaveHook调用 function getRouteHooksForRoutes(routes) { return routes.map(function (route) { return RouteHooks[getRouteID(route)]; }).filter(function (hook) { return hook; }); } // 执行用户调用transitionManager.listenBeforeLeavingRoute(route,hook)添加的前置钩子执行函数 // 返回值result交给封装了迭代器next、done方法的callback回调处理 function transitionHook(location,callback) { // matchRoutes(routes,params}形式 // 并且将{routes,params}传入回调callback函数作为参数nextState (0,nextState) { if (nextState == null) { callback(); return; } partialNextState = _extends({},{ location: location }); // 获取用户调用transitionManager.listenBeforeLeavingRoute(hook)添加的前置钩子执行函数 // _computeChangedRoutes3.default(prevState,nextState)计算确切的changeRoutes、leaveRoutes、enterRoutes var hooks = getRouteHooksForRoutes((0,partialNextState).leaveRoutes); var result = void 0; for (var i = 0,len = hooks.length; result == null && i < len; ++i) { result = hooks[i](location); } callback(result); }); } function beforeUnloadHook() { // Synchronously check to see if any route hooks want // to prevent the current window/tab from closing. if (state.routes) { var hooks = getRouteHooksForRoutes(state.routes); var message = void 0; for (var i = 0,len = hooks.length; typeof message !== 'string' && i < len; ++i) { // Passing no args indicates to the user that this is a // beforeunload hook. We don't know the next location. message = hooks[i](); } return message; } } var unlistenBefore = void 0,unlistenBeforeUnload = void 0; function removeListenBeforeHooksForRoute(route) { var routeID = getRouteID(route); if (!routeID) { return; } delete RouteHooks[routeID]; if (!hasAnyProperties(RouteHooks)) { if (unlistenBefore) { unlistenBefore(); unlistenBefore = null; } if (unlistenBeforeUnload) { unlistenBeforeUnload(); unlistenBeforeUnload = null; } } } // 添加离开某route时执行的函数hook,通过history.listenBefore添加前置钩子实现 // 事件触发时通过computeChangedRoutes计算变更前后的state获取leaveRoutes,从RouteHooks得到添加函数hook并执行 // hook返回否值阻止页面跳转;返回字符串将弹出警告窗口,该机制在history模块中实现 function listenBeforeLeavingRoute(route,hook) { var thereWereNoRouteHooks = !hasAnyProperties(RouteHooks); // 以RouteGuid创建route的__id__属性后返回 var routeID = getRouteID(route,true); RouteHooks[routeID] = hook; if (thereWereNoRouteHooks) { // history.listenBefore添加前置钩子,路径变更触发时借由histroy模块中histroy.js文件下confirmTransitionTo函数执行 // confirmTransitionTo函数以updateLocation变更路径函数作为内置回调 // 因此实现了前置钩子执行完成后,更迭路径数据及变更页面路径 // 前置钩子以待变更路径数据location作为首参,封装迭代器方法next、done的函数作为次参,由confirmTransitionTo执行函数传入 // transitionHook函数将执行listenBeforeLeavingRoute添加的hook函数 // hook返回false时中止页面路径改变 unlistenBefore = history.listenBefore(transitionHook); // history.listenBeforeUnload??? if (history.listenBeforeUnload) unlistenBeforeUnload = history.listenBeforeUnload(beforeUnloadHook); } return function () { removeListenBeforeHooksForRoute(route); }; } // Router模块中内部使用,挂载指定回调,即更新Router组件及触发组件的props.onUpdate方法执行 function listen(listener) { function historyListener(location) { if (state.location === location) { listener(null,state); } else { // 获取state信息为{routes,component}形式,执行回调 // 期间触发Route组件配置的route.onChange|onEnter|onLeave方法执行 match(location,redirectLocation,nextState) { if (error) { listener(error); } else if (redirectLocation) { history.replace(redirectLocation); } else if (nextState) { listener(null,nextState); } else { process.env.NODE_ENV !== 'production' ? (0,_routerWarning2.default)(false,'Location "%s" did not match any routes',location.pathname + location.search + location.hash) : void 0; } }); } } // 监听hashChange或popstate事件,绑定回调函数historyListener var unsubscribe = history.listen(historyListener); // 初始化更新Router组件及触发组件的props.onUpdate方法执行 if (state.location) { listener(null,state); } else { historyListener(history.getCurrentLocation()); } // 返回解绑函数 return unsubscribe; } return { // isActive(location,indexOnly)判断location同当前路径是否相同 // indexOnly为真值时路径pathname需要完全匹配,否则pathname匹配激活的route设下的路由规则即可 // IndexRouter、IndexRedirect组件使用,判断是否根路径 isActive: isActive,// 内部listen方法调动,match(location,callback)参数location变更后的路径数据 // 获取激活的Route信息、待挂载的组件信息、路径变量信息(即state数据信息) // state以{routes,component}形式传入callback中,并执行callback // 期间触发Route组件配置的route.onChange|onEnter|onLeave方法执行 match: match,// listenBeforeLeavingRoute(route,hook)添加离开某route时执行的函数hook // 通过history.listenBefore添加前置钩子实现 // 事件触发时通过computeChangedRoutes计算变更前后的state获取leaveRoutes,从RouteHooks得到添加函数hook并执行 // hook返回否值阻止页面跳转;返回字符串将弹出警告窗口,该机制在history模块中实现 listenBeforeLeavingRoute: listenBeforeLeavingRoute,// 监听hashChange或popstate事件,回调中更新Router组件及触发组件的props.onUpdate方法执行 listen: listen }; } module.exports = exports['default'];

3.RouterUtils.js

Router.js模块中调用,用于创建this.router对象。

this.router通过拷贝形式获得histroy的方法,因此能操作变更路径、绑点函数等;同时this.router获得this.transition的isActive(location,indexOnly)方法,setRouteLeaveHook(route,hook)方法也引用this.transition的listenBeforeLeavingRoute方法;this.router还获得location、params、routes属性,用于访问当前页面下路径数据、路径变量和激活的route元素。

Router组件的this.router通过getChildContext传入子组件如Link、IndexLink、及使用withRouter(WrappedComponent)形式挂载的WrappedComponent元素中。这些元素的this.context.router即指向Router组件的this.router。Link、IndexLink组件调用this.context.router.push | createHref实现点击跳转功能;WrappedComponent组件通过this.context.router向props注入{router,routes},元素由对应的路径数据、路径变量、激活的route元素完成实例化。

Router.js模块提供createRouterObject、assignRouterState两个方法。createRouterObject用于创建this.router对象,assignRouterState用于路径变更,引起Router组件setState方法执行前,更新this.router的location、params、routes属性指向待变更路径数据的对应属性

this.router的属性方法

location 当前页面的路径数据

params 当前页面的路径变量

routes 当前页面激活的route元素,包含Route、IndexRoute、Redirect、IndexRedirect元素

isActive(location,indexOnly) 判断location路径数据是否符合激活route元素设定的路由规则;indexOnly为真值时,pathname须严格相等,对应IndexRoute、IndexRedirect情形。

setRouteLeaveHook(route,hook) 页面离开route元素时,执行hook函数。hook返回值为字符串,弹框提示;为否值时,阻止页面跳转

部分方法以及源自history模块:

getCurrentLocation 获取当前页面的location路径数据。

listenBefore( function hook(location,callback){} ) 添加前置钩子hook。hook函数的参数location、callback都由history模块的内部机制传入。其中,首参location为待跳转页面路径数据;次参callback为封装了迭代器next、done方法函数,用于控制流程。hook返回否值,阻止页面跳转;返回字符串,弹框提示

listen( function listener(location){} ) 添加后置钩子listener,页面跳转时执行的回调函数

push(nextPath)、replace(nextPath)@R_386_404@面,将触发前置钩子和后置钩子的执行。

go、goBack、goForward 通过window.history.go@R_386_404@面。

createPath(location)、createHref(location) 生成路径。

@H_403_13@"use strict"; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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; }; // createRouterObject(history,state)方法 // 创建复合对象,含有histroy绑定路由事件、获取路由数据、跳转路由相关方法 // 以及setRouteLeaveHook、isActive方法 // 及location、params、routes属性(同Router组件当前state的相关属性等值) exports.createRouterObject = createRouterObject; // assignRouterState(router,_ref)拷贝_ref的location、params、routes属性给router // 次参_ref通常是Router组件当前的state,用于更新createRouterObject创建的复合对象的state相关数据 exports.assignRouterState = assignRouterState; // histroy为hashHistory、broswerHistroy、memoryHistory内含绑定路由事件、获取路由数据、跳转路由相关方法 // 复合histroy的属性方法添加setRouteLeaveHook、isActive方法,location、params、routes属性后返回 function createRouterObject(history,state) { var router = _extends({},history,{ setRouteLeaveHook: transitionManager.listenBeforeLeavingRoute,isActive: transitionManager.isActive }); return assignRouterState(router,state); } // 拷贝次参对象的location、params、routes属性给首参对象 // Router.js模块中调用,用于路径变更时更新this.router.location | params | routes信息 function assignRouterState(router,_ref) { var location = _ref.location,params = _ref.params,routes = _ref.routes; router.location = location; router.params = params; router.routes = routes; return router; }

4.RouterContent.js

RouterContent.js实现Route、IndexRoute元素所挂载组件的渲染,props={router,createElement}借由Router.js监听hashChange、popstate事件触发setState方法执行、完成更迭。

当通过<Route path="message/:id" component={Component}/>挂载Component元素时,该Component元素的props形式为{location,router,route,routeParams},其中location,routes为当前页面对应的路径数据、路径变量、激活的route元素(如Route、IndexRoute、Redirect、IndexRedirect元素);router为Router元素的this.router,用于操作页面跳转、监听路径跳转获取当前的路径数据等;route为该Component元素相应的Route或IndexRoute元素;routeParams为与该Component元素对应的Route,其下设的路径变量数据,如{id:1}形式。

特别的,当通过<Route path="/" component={App}><Routepath="message/:id"components={key:Component}/> </Route>挂载Component元素时,父元素App将获得props.key=Component,用于render方法渲染绘制。

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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 Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); var _react = require('react'); var _react2 = _interoprequiredefault(_react); // 通过route获取路径变量的键,再注入params相应键的值,意为当前route路径的变量 var _getRouteParams = require('./getRouteParams'); var _getRouteParams2 = _interoprequiredefault(_getRouteParams); var _ContextUtils = require('./ContextUtils'); // 提供一系列方法,目的是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 // 其中isReactChildren(element)方法用于校验单个或一组元素是否reactElement var _RouteUtils = require('./RouteUtils'); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _React$PropTypes = _react2.default.PropTypes,array = _React$PropTypes.array,object = _React$PropTypes.object; // 负责渲染Router下子Route挂载的组件,由Router的state数据获取到激活的Route组件及其components待挂载的组件 // 通过底层的Route组件向上遍历父Route,创建待挂载渲染的props.component|components组件元素reactElement实现 var RouterContext = _react2.default.createClass({ displayName: 'RouterContext',// 向下游组件通过context传递this.context[contextName].subscribe添加绑定事件方法 // this.context[contextName].eventIndex访问跳转路径发生次数 // 意义是下游组件如Link通过绑定函数监听路径变化事件发生,并重绘Link组件 mixins: [(0,_ContextUtils.ContextProvider)('router')],propTypes: { router: object.isrequired,// 通过Router组件的this.router传入,操作路由、获取数据方法属性 location: object.isrequired,// 路径信息数据 routes: array.isrequired,// 当前路径下被激活的Route组件 params: object.isrequired,// 路径变量 components: array.isrequired,// 待挂载渲染的组件 createElement: func.isrequired// 通过Router组件的props传入,用户未设置,默认为react.createElement },// props.createElement默认赋值为react.createElement getDefaultProps: function getDefaultProps() { return { createElement: _react2.default.createElement }; },childContextTypes: { router: object.isrequired },// 向子Route传递router,即Router组件的this.router,可操作路由、获取数据方法属性 getChildContext: function getChildContext() { return { router: this.props.router }; },createElement: function createElement(component,props) { return component == null ? null : this.props.createElement(component,props); },render: function render() { var _this = this; var _props = this.props,location = _props.location,params = _props.params,components = _props.components,router = _props.router; var element = null; if (components) { // 由底层向上创建待挂载渲染的route.props.component|components组件元素 element = components.reduceRight(function (element,index) { if (components == null) return element; // Don't create new children; use the grandchildren. var route = routes[index]; var routeParams = (0,_getRouteParams2.default)(route,params); var props = { location: location,route: route,router: router,routeParams: routeParams,routes: routes }; // 校验element是否react元素(可以是数组形式),嵌套子Route待挂载的组件,作为父组件的props.children if ((0,_RouteUtils.isReactChildren)(element)) { props.children = element; // 子Route使用components={key:component}形式定义待挂载的组件,父组件通过this.props[key]获取元素 } else if (element) { for (var prop in element) { if (Object.prototype.hasOwnProperty.call(element,prop)) props[prop] = element[prop]; } } // Route使用components={key:component}形式定义待挂载的组件,创建react元素 if ((typeof components === 'undefined' ? 'undefined' : _typeof(components)) === 'object') { var elements = {}; for (var key in components) { if (Object.prototype.hasOwnProperty.call(components,key)) { elements[key] = _this.createElement(components[key],_extends({ key: key },props)); } } return elements; } return _this.createElement(components,props); },element); } !(element === null || element === false || _react2.default.isValidElement(element)) ? process.env.NODE_ENV !== 'production' ? (0,'The root route must render a single element') : (0,_invariant2.default)(false) : void 0; return element; } }); exports.default = RouterContext; module.exports = exports['default'];

5.Route.js、IndexRoute.js

Route用于约定某路由下待加载的组件,JSX书写方式为<Route path="pathname" component={Component}/>。特别的,IndexRoute用于约定父Route默认加载的组件,JSX书写方式为<Route path="pathname1" component={Component1}><IndexRoutecomponent={Component2}/><Route path="pathname2" component={Component3}/></Route>,即pathname1路径下将渲染Component2,pathname1/pathname2路径下将渲染Component3。

Route、IndexRoute组件不负责渲染,用于向Router组件提供props.routes(形式为[{path:"",component:Component}])。path用于定义路由匹配规则,component | components | getComponent | getComponents定义待加载的组件。Router.js模块调用this.transition.listen方法监听hashChange、popstate事件时,绑点函数将通过matchRoutes.js模块的matchRoutes方法,由当前页面路径逐个匹配Router组件props.routes下的路由规则,获得被激活的routes元素(包含Route、IndexRoute、Redirect、IndexRedirect元素),从而得到当前页面下待加载的组件。

Route、IndexRoute组件提供createRouteFromReactElement静态方法,实现功能为:当Route、IndexRoute、Redirect、IndexRedirect元素使用JSX语法添加到Router元素下时,Router.js模块将调用RouteUtils.js模块的creatRoutes方法将JSX语法书写的Route、IndexRoute、Redirect、IndexRedirect元素转化为props.routes形式,供matchRoutes.js模块使用。

Route、IndexRoute元素可设置的事件:

props.onLeave(prevState) 离开时调用函数

props.onChange(state,replace) 路径改变时调用函数,replace即history.replace(location)方法,用 于页面跳转

props.onEnter(nextState,replace) route激活时调用函数

Route.js源码

@H_403_13@'use strict'; exports.__esModule = true; var _react = require('react'); var _react2 = _interoprequiredefault(_react); // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); // 提供一系列方法,目的是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 var _RouteUtils = require('./RouteUtils'); var _InternalPropTypes = require('./InternalPropTypes'); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _React$PropTypes = _react2.default.PropTypes,string = _React$PropTypes.string,func = _React$PropTypes.func; // var props={ // path: string,// 对应的页面路径 // component,// 待渲染的组件 // components,// 键值对形式设置加载的子组件,其中键作为props.key // getComponent,// 函数形式获取加载的子组件 // getComponents,// onLeave(prevState),// 离开时调用函数 // onChange(state,replace),// 路径改变时调用函数 // onEnter(nextState,// route激活时调用函数 // } // <Route {...props}> // 用于定义某路径下待加载的components组件,以及离开、进入、跳转时执行的函数,渲染components通过RouterContent模块实现 // 由matchRoutes模块获取当前路径下激活的route及indexRoute及Redirect元素 // 再通过createTransitionManager模块根据激活的route获取待加载的组件 // 最后Router绑定hashchange事件setState时重绘组件 var Route = _react2.default.createClass({ displayName: 'Route',// 添加静态属性方法 // createRouteFromReactElement静态方法在RouteUtils模块中使用 // 作用是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 // 子Route组件作为父Route组件的props.childRoutes属性 statics: { createRouteFromReactElement: _RouteUtils.createRouteFromReactElement },propTypes: { path: string,// 对应的页面路径 component: _InternalPropTypes.component,// 待渲染的组件 components: _InternalPropTypes.components,// 键值对形式设置加载的子组件,其中键作为props.key getComponent: func,// 函数形式获取加载的子组件 getComponents: func //onLeave(prevState) 离开时调用函数 //onChange(state,replace) 路径改变时调用函数 //onEnter(nextState,replace) route激活时调用函数 },// 不负责渲染 render: function render() { !false ? process.env.NODE_ENV !== 'production' ? (0,'<Route> elements are for router configuration only and should not be rendered') : (0,_invariant2.default)(false) : void 0; } }); exports.default = Route; module.exports = exports['default'];

IndexRoute.js源码

@H_403_13@'use strict'; exports.__esModule = true; var _react = require('react'); var _react2 = _interoprequiredefault(_react); // 封装warning模块,目的是使含'deprecated'的警告文案只提示一次 var _routerWarning = require('./routerWarning'); var _routerWarning2 = _interoprequiredefault(_routerWarning); // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); // 提供一系列方法,目的是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 var _RouteUtils = require('./RouteUtils'); var _InternalPropTypes = require('./InternalPropTypes'); function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var func = _react2.default.PropTypes.func; // <Router> // <Route path="/" component={App}> // <IndexRoute component={Home}/> // <Route path="accounts" component={Accounts}/> // <Route path="statements" component={Statements}/> // </Route> // </Router> // JSX书写IndexRoute,意义是访问"/"路径时加载Home模块,作为根路径下加载的子模块 // IndexRoute必然作为Route的子组件,JSX配置转化为类props配置时,父route获得indexRoute属性指向子IndexRoute // 由matchRoutes模块获取当前路径下激活的route及indexRoute及Redirect元素 // 再通过createTransitionManager模块根据激活的route获取待加载的组件 // 最后Router绑定hashchange事件setState时重绘组件 var IndexRoute = _react2.default.createClass({ displayName: 'IndexRoute',// createRouteFromReactElement静态方法在RouteUtils模块中使用 // 作用是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 statics: { createRouteFromReactElement: function createRouteFromReactElement(element,parentRoute) { if (parentRoute) { // IndexRoute组件作为父Route组件的props.childRoutes属性的同时,也作为其indexRoute属性 parentRoute.indexRoute = (0,_RouteUtils.createRouteFromReactElement)(element); } else { process.env.NODE_ENV !== 'production' ? (0,'An <IndexRoute> does not make sense at the root of your route config') : void 0; } } },propTypes: { path: _InternalPropTypes.falsy,component: _InternalPropTypes.component,components: _InternalPropTypes.components,getComponent: func,getComponents: func },render: function render() { !false ? process.env.NODE_ENV !== 'production' ? (0,'<IndexRoute> elements are for router configuration only and should not be rendered') : (0,_invariant2.default)(false) : void 0; } }); exports.default = IndexRoute; module.exports = exports['default'];

6.Redirect.js、IndexRedirect.js

Redirect.js模块实现,当用户访问指定路径时,将页面跳转到另一指定路径。

IndexRedirect.js模块实现,当用户访问IndexRedirect元素的父Route元素的路径时,将页面跳转到指定路径。

实现机制是,Redirect、IndexRedirect组件也设置createRouteFromReactElement静态方法获取route,当Router组件调用RouteUtils.createRoutes方法时也将Redirect、IndexRedirect转化为props.routes内数据。因此当hashChange、popState事件触发时,也将获得激活的Redirect、IndexRedirect元素,并调用route.onEnter跳转到props.to路径下。

Redirect.js源码

@H_403_13@'use strict'; exports.__esModule = true; var _react = require('react'); var _react2 = _interoprequiredefault(_react); // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); // 提供一系列方法,目的是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 var _RouteUtils = require('./RouteUtils'); // 通过histroy设定的路径格式获取真实路径的正则匹配规则,或获取真实路径的路径变量,或通过路径变量和路径格式获取真实路径 var _PatternUtils = require('./PatternUtils'); var _InternalPropTypes = require('./InternalPropTypes'); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _React$PropTypes = _react2.default.PropTypes,object = _React$PropTypes.object; // <Route path="inBox" component={InBox}> // { 从 /inBox/messages/:id 跳转到 /messages/:id } // <Redirect from="messages/:id" to="/messages/:id" /> // </Route> // 重定向页面路径 var Redirect = _react2.default.createClass({ displayName: 'Redirect',statics: { // matchRoutes模块通过调用RouteUtils模块中间接执行,用于判断Redirect元素是否被激活 createRouteFromReactElement: function createRouteFromReactElement(element) { // 获取Redirect元素的props配置 // 同时在matchRoutes模块中根据当前路径获取的激活routes,将根据由Redirect元素得到的route.path // 判断是否需要将Redirect元素的props配置,也加入激活的routes中 var route = (0,_RouteUtils.createRouteFromReactElement)(element); if (route.from) route.path = route.from; // Redirect元素激活,creatTransitionManager模块调用Redirect元素的props.onEnter,页面重定向 route.onEnter = function (nextState,replace) { var location = nextState.location,params = nextState.params; var pathname = void 0; if (route.to.charAt(0) === '/') { pathname = (0,_PatternUtils.formatPattern)(route.to,params); } else if (!route.to) { pathname = location.pathname; } else { var routeIndex = nextState.routes.indexOf(route); var parentPattern = Redirect.getRoutePattern(nextState.routes,routeIndex - 1); var pattern = parentPattern.replace(/\/*$/,'/') + route.to; pathname = (0,_PatternUtils.formatPattern)(pattern,params); } replace({ pathname: pathname,query: route.query || location.query,state: route.state || location.state }); }; // matchRoutes模块中判断Redirect是否在激活状态 // 若激活,通过creatTransitionManager模块调用Redirect元素的props.onEnter,页面重定向 return route; },getRoutePattern: function getRoutePattern(routes,routeIndex) { var parentPattern = ''; for (var i = routeIndex; i >= 0; i--) { var route = routes[i]; var pattern = route.path || ''; parentPattern = pattern.replace(/\/*$/,'/') + parentPattern; if (pattern.indexOf('/') === 0) break; } return '/' + parentPattern; } },from: string,// Alias for path to: string.isrequired,query: object,state: object,onEnter: _InternalPropTypes.falsy,children: _InternalPropTypes.falsy },'<Redirect> elements are for router configuration only and should not be rendered') : (0,_invariant2.default)(false) : void 0; } }); exports.default = Redirect; module.exports = exports['default'];

IndexRedirect.js源码

@H_403_13@'use strict'; exports.__esModule = true; var _react = require('react'); var _react2 = _interoprequiredefault(_react); // 封装warning模块,目的是使含'deprecated'的警告文案只提示一次 var _routerWarning = require('./routerWarning'); var _routerWarning2 = _interoprequiredefault(_routerWarning); // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); var _Redirect = require('./Redirect'); var _Redirect2 = _interoprequiredefault(_Redirect); var _InternalPropTypes = require('./InternalPropTypes'); function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _React$PropTypes = _react2.default.PropTypes,object = _React$PropTypes.object; // <Route path="/" component={App}> // <IndexRedirect to="/welcome" /> // <Route path="welcome" component={Welcome} /> // <Route path="about" component={About} /> // </Route> // 根路径下重定向页面路径 var IndexRedirect = _react2.default.createClass({ displayName: 'IndexRedirect',statics: { createRouteFromReactElement: function createRouteFromReactElement(element,parentRoute) { // 调用Redirect.createRouteFromReactElement获取IndexRedirect元素的props配置 // 同时,父元素route的indexRoute添加该props配置,实现也就跟IndexRoute组件相同 if (parentRoute) { parentRoute.indexRoute = _Redirect2.default.createRouteFromReactElement(element); } else { process.env.NODE_ENV !== 'production' ? (0,'An <IndexRedirect> does not make sense at the root of your route config') : void 0; } } },propTypes: { to: string.isrequired,'<IndexRedirect> elements are for router configuration only and should not be rendered') : (0,_invariant2.default)(false) : void 0; } }); exports.default = IndexRedirect; module.exports = exports['default'];

7.Link.js、IndexLink.js

Link.js、IndexLink.js实现点击跳转功能,实现机制是通过this.context.router获得Router元素的this.router,在监听点击事件的绑定函数内部调用this.context.router.push方法跳转链接

特别的,IndexLink组件设置样式时将向this.context.router.isActive方法传入indexOnly=true参数,待跳转的路径pathname须与当前页面路径的pathname完全匹配,IndexLink元素添加activeClassName、activeStyle样式。而Link元素的机制是,通过当前页面路径获取路由规则state.location、state.routes、state.params,只要待跳转的路径pathname匹配该路由规则,当即添加activeClassName、activeStyle样式。

hashChange、popstate事件触发、Router更新state时,Link、IndexLink元素将通过ContextUtils.js机制实现WrappedComponent元素的重新渲染

Link.js源码:

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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 _react = require('react'); var _react2 = _interoprequiredefault(_react); // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); var _PropTypes = require('./PropTypes'); // RouterContext模块向下游组件通过context传递subscribe方法添加绑定事件方法,eventIndex获取跳转路径发生次数 // Link组件通过绑定函数监听路径变化事件发生,并调用setState重绘Link组件 var _ContextUtils = require('./ContextUtils'); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // obj的属性方法在keys中也有,不予拷贝 function _objectWithoutProperties(obj,bool = _React$PropTypes.bool,object = _React$PropTypes.object,oneOfType = _React$PropTypes.oneOfType; function isLeftClickEvent(event) { return event.button === 0; } function isModifiedEvent(event) { return !!(event.MetaKey || event.altKey || event.ctrlKey || event.shiftKey); } function isEmptyObject(object) { for (var p in object) { if (Object.prototype.hasOwnProperty.call(object,p)) return false; }return true; } function resolveToLocation(to,router) { return typeof to === 'function' ? to(router.location) : to; } // var props={ // to,// 待跳转的路径数据,string如`/posts/${post.id}`,object,function(router.location)以当前页面路径作为参数 // query:object,// hash: string,// state: object,// activeStyle,// props.to指向的路径为页面当前路径时,添加的样式 // activeClassName,// props.to指向的路径为页面当前路径时,添加的样式 // onlyActiveOnIndex,// activeClassName添加时待@R_386_404@面是否需要严格匹配路径 // onClick: func,// 点击事件触发时执行函数 // target: string// "_blank"链接打开的方式 // } // <Route path="/posts/:postID" component={Post} > // <Link to={`/posts/${post.id}`} /> // <Link ... query={{ show: true }} state={{ the: 'state' }} /> // </Route> // 提供页面路径跳转功能,通过router.push方法实现,也即能触发Router下组件重绘 var Link = _react2.default.createClass({ displayName: 'Link',// Router下游Link监听路径变化事件发生,调用setState方法重绘组件 mixins: [(0,_ContextUtils.ContextSubscriber)('router')],contextTypes: { router: _PropTypes.routerShape },propTypes: { to: oneOfType([string,object,func]),hash: string,activeStyle: object,activeClassName: string,onlyActiveOnIndex: bool.isrequired,onClick: func,target: string },getDefaultProps: function getDefaultProps() { return { onlyActiveOnIndex: false,style: {} }; },// 点击时通过router.push@R_386_404@面,router.push也即histroy.push方法 handleClick: function handleClick(event) { if (this.props.onClick) this.props.onClick(event); if (event.defaultPrevented) return; var router = this.context.router; !router ? process.env.NODE_ENV !== 'production' ? (0,'<Link>s rendered outside of a router context cannot navigate.') : 0,_invariant2.default)(false) : void 0; if (isModifiedEvent(event) || !isLeftClickEvent(event)) return; if (this.props.target) return; event.preventDefault(); router.push(resolveToLocation(this.props.to,router)); },render: function render() { var _props = this.props,to = _props.to,activeClassName = _props.activeClassName,activeStyle = _props.activeStyle,onlyActiveOnIndex = _props.onlyActiveOnIndex,props = _objectWithoutProperties(_props,['to','activeClassName','activeStyle','onlyActiveOnIndex']); var router = this.context.router; if (router) { if (to == null) { return _react2.default.createElement('a',props); } var toLocation = resolveToLocation(to,router); props.href = router.createHref(toLocation); if (activeClassName || activeStyle != null && !isEmptyObject(activeStyle)) { if (router.isActive(toLocation,onlyActiveOnIndex)) { if (activeClassName) { if (props.className) { props.className += ' ' + activeClassName; } else { props.className = activeClassName; } } if (activeStyle) props.style = _extends({},props.style,activeStyle); } } } return _react2.default.createElement('a',_extends({},{ onClick: this.handleClick })); } }); exports.default = Link; module.exports = exports['default'];

IndexLink源码

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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 _react = require('react'); var _react2 = _interoprequiredefault(_react); var _Link = require('./Link'); var _Link2 = _interoprequiredefault(_Link); function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // <IndexLink to="/" activeClassName="active"> // Home // </IndexLink> // 跳转到根路径 var IndexLink = _react2.default.createClass({ displayName: 'IndexLink',render: function render() { return _react2.default.createElement(_Link2.default,this.props,{ onlyActiveOnIndex: true })); } }); exports.default = IndexLink; module.exports = exports['default'];

8.withRouter.js

withRouter.js模块用于将react组件WrappedComponent封装为高阶组件,并向WrappedComponent元素的props注入router操控路由、params当前页面的路径变量、location当前页面的路径数据、routes当前页面激活的route元素。同Link组件,hashChange、popstate事件触发、Router更新state时,将通过ContextUtils.js机制实现WrappedComponent元素的重新渲染。

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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; }; exports.default = withRouter; // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); var _react = require('react'); var _react2 = _interoprequiredefault(_react); var _hoistNonReactStatics = require('hoist-non-react-statics'); var _hoistNonReactStatics2 = _interoprequiredefault(_hoistNonReactStatics); var _ContextUtils = require('./ContextUtils'); var _PropTypes = require('./PropTypes'); function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; } // 与Link组件的机制相同,context获得subscribe方法添加绑定事件方法,eventIndex属性获取跳转路径发生次数 // 通过subscribe方法挂载withRouter的setState重绘方法,当RouterContent组件的componentDidUpdate方法触发时执行 // 同时props.router属性获得Router创建router,可用于操纵路由、获取路径数据 // 使用同普通组件一样,作为route的props.component属性 function withRouter(WrappedComponent,options) { var withRef = options && options.withRef; var WithRouter = _react2.default.createClass({ displayName: 'WithRouter',mixins: [(0,contextTypes: { router: _PropTypes.routerShape },propTypes: { router: _PropTypes.routerShape },getWrappedInstance: function getWrappedInstance() { !withRef ? process.env.NODE_ENV !== 'production' ? (0,'To access the wrapped instance,you need to specify ' + '`{ withRef: true }` as the second argument of the withRouter() call.') : (0,_invariant2.default)(false) : void 0; return this.wrappedInstance; },render: function render() { var _this = this; var router = this.props.router || this.context.router; var params = router.params,location = router.location,routes = router.routes; var props = _extends({},{ router: router,routes: routes }); if (withRef) { props.ref = function (c) { _this.wrappedInstance = c; }; } return _react2.default.createElement(WrappedComponent,props); } }); WithRouter.displayName = 'withRouter(' + getDisplayName(WrappedComponent) + ')'; WithRouter.WrappedComponent = WrappedComponent; return (0,_hoistNonReactStatics2.default)(WithRouter,WrappedComponent); } module.exports = exports['default'];

9.browserHistory.js、hashHistory.js、createMemoryHistory.js

browserHistory.js模块由histroy模块创建的browserHistory对象,用于@R_386_404@面,监听hashChange、popstate事件,获取当前页面路径数据等。

hashHistory.js模块由histroy模块创建的hashHistory对象,用于@R_386_404@面,监听hashChange、popstate事件,获取当前页面路径数据等。

createMemoryHistory.js模块调用histroy模块的createMemoryHistory,用于创建memoryHistory对象,实现@R_386_404@面,监听hashChange、popstate事件,获取当前页面路径数据等。

各history对象作为Router元素的props.history,使Router实现监听hashChange、popstate事件并更新state、重绘组件,以及this.router获得@R_386_404@面、添加前置钩子等方法

browserHistory.js源码

@H_403_13@'use strict'; exports.__esModule = true; // createBrowserHistory(options),构建browserHistory对象,内含变更页面路径到更新location数据到执行绑点函数的一般方法 // options.forceRefresh 强制使用window.location.href(path)或window.location.replace(path)更新页面路径 // 返回值 // { // getUserConfirmation,// getUserConfirmation(message,callback) 在callback回调中定制执行window.confirm(message) // forceRefresh,// 强制使用window.location.href(path)或window.location.replace(path)更新页面路径 // getCurrentLocation,// 获取当前location数据{pathname,search,hash,action,key} // pushLocation,// 路径重新赋值,并使用window.sessionStorage存储{[key]:state}形式的location路径数据 // replaceLocation,// 路径重新赋值,并使用window.sessionStorage存储{[key]:state}形式的location路径数据 // listenBefore,// 将transitionTo方法绑定到popState或hashChange事件上,添加前置钩子;事件触发时,执行钩子,及变更浏览器location及window.sessionStorage存储 // listen,// 将transitionTo方法绑定到popState或hashChange事件上,添加后置钩子;事件触发时,执行钩子,及变更浏览器location及window.sessionStorage存储 // transitionTo,// 变更页面路径、更新window.sessionStorage、执行钩子函数,更新allKeys,可作为页面路径变更时的回调 // push,// transitionTo方法变更页面路径、更新window.sessionStorage、执行钩子函数,allKeys添加一条路径记录,可作为页面路径变更时的回调 // replace,// transitionTo方法变更页面路径、更新window.sessionStorage、执行钩子函数,allKeys替换一条路径记录,可作为页面路径变更时的回调 // go,// window.history.go@R_386_404@面 // goBack,// window.history.go@R_386_404@面 // goForward,// window.history.go@R_386_404@面 // createKey,// 随机生成一个key,作为查询字符串中的值,以及window.sessionStorage中的键 // createPath,// 生成路径 // createHref,// 生成路径 // createLocation,// 生成location数据 // } var _createBrowserHistory = require('history/lib/createBrowserHistory'); var _createBrowserHistory2 = _interoprequiredefault(_createBrowserHistory); // 装饰createHistory函数后,并调用createHistory创建history对象 var _createRouterHistory = require('./createRouterHistory'); var _createRouterHistory2 = _interoprequiredefault(_createRouterHistory); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // 创建history对象 // { // getUserConfirmation,// 默认值false,即不使用window.location.href(path)或window.location.replace(path)更新页面路径 // getCurrentLocation,// 生成location数据 // } exports.default = (0,_createRouterHistory2.default)(_createBrowserHistory2.default); module.exports = exports['default'];

hashHistory.js、createRouterHistory.js源码

@H_403_13@'use strict'; exports.__esModule = true; // createHashHistory(options),创建hashHistory对象,内含变更页面路径到更新location数据到执行绑点函数的一般方法 // options.queryKey 不能设置为false,哈希路径中查询字符串的键,值为window.sessionStorage存储state的键 // options.hashType 须是hashbang、noslash、slash中的一个,默认slash,规定哈希路径hashPath类型 // hashbang以"!"起始,noslash直接跟路径,slash以"/"起始 // 返回值 // { // getUserConfirmation,callback) 在callback回调中定制执行window.confirm(message) // queryKey,// 哈希路径中查询字符串的键,值为window.sessionStorage存储state的键 // hashType,// 规定哈希路径hashPath书写形式 // getCurrentLocation,// 哈希路径重新赋值,并使用window.sessionStorage存储{[key]:state}形式的location哈希路径数据 // replaceLocation,// 哈希路径重新赋值,并使用window.sessionStorage存储{[key]:state}形式的location哈希路径数据 // listenBefore,// 将transitionTo方法绑定到hashChange事件上,添加前置钩子;事件触发时,执行钩子,及变更浏览器location及window.sessionStorage存储 // listen,// 将transitionTo方法绑定到hashChange事件上,添加后置钩子;事件触发时,执行钩子,及变更浏览器location及window.sessionStorage存储 // transitionTo,// 生成哈希路径 // createLocation,// 生成location数据 // } var _createHashHistory = require('history/lib/createHashHistory'); var _createHashHistory2 = _interoprequiredefault(_createHashHistory); // 装饰createHistory函数后,并调用createHistory创建history对象 var _createRouterHistory = require('./createRouterHistory'); var _createRouterHistory2 = _interoprequiredefault(_createRouterHistory); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // 创建history对象 // { // getUserConfirmation,// 默认值'_k',哈希路径中查询字符串的键,值为window.sessionStorage存储state的键 // hashType,// 默认值"slash",规定哈希路径hashPath书写形式 // getCurrentLocation,_createRouterHistory2.default)(_createHashHistory2.default); module.exports = exports['default']; @H_403_13@'use strict'; exports.__esModule = true; // 装饰createHistory函数后,并调用createHistory创建history对象 exports.default = function (createHistory) { var history = void 0; if (canUseDOM) history = (0,_useRouterHistory2.default)(createHistory)(); return history; }; // useRouterHistory(createHistory),装饰createHistory函数,操作location数据对象时query查询字符串序列化对象、basename基础路径 var _useRouterHistory = require('./useRouterHistory'); var _useRouterHistory2 = _interoprequiredefault(_useRouterHistory); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); module.exports = exports['default'];

createMemoryHistory.js

@H_403_13@'use strict'; exports.__esModule = true; exports.default = createMemoryHistory; // 装饰createHistory函数,操作location数据对象时分离query查询字符串对象,返回装饰函数 var _useQueries = require('history/lib/useQueries'); var _useQueries2 = _interoprequiredefault(_useQueries); // 装饰createHistory函数,操作location数据对象时分离basename,返回装饰函数 var _useBasename = require('history/lib/useBasename'); var _useBasename2 = _interoprequiredefault(_useBasename); // createMemoryHistory(options),使用js闭包缓存特点构建{key:state}存储机制,存储在闭包变量storage中 // options.entries options为路径对象{path,key,state}构成的数组时,将options赋值给options.entries; // options为字符串时,将[options]赋值给options.entries // options.current 默认取options.entries.length-1 // 返回值 // { // entries,// {path,state}对象构成的路径数据数组 // getCurrentLocation,// entries、storage添加一条路径记录 // replaceLocation,// entries、storage替换一条路径记录 // listenBefore,// 添加后置钩子 // listen,// 添加后置钩子 // transitionTo,// 变更页面路径、更新storage、执行钩子函数,更新allKeys,可作为页面路径变更时的回调 // push,// transitionTo方法变更页面路径、更新storage、执行钩子函数,allKeys添加一条路径记录,可作为页面路径变更时的回调 // replace,// transitionTo方法变更页面路径、更新storage、执行钩子函数,allKeys替换一条路径记录,可作为页面路径变更时的回调 // go,// 变更页面路径、更新storage、执行钩子函数,更新allKeys // goBack,// 生成location数据 // } var _createMemoryHistory = require('history/lib/createMemoryHistory'); var _createMemoryHistory2 = _interoprequiredefault(_createMemoryHistory); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function createMemoryHistory(options) { var memoryHistory = (0,_createMemoryHistory2.default)(options); var createHistory = function createHistory() { return memoryHistory; }; var history = (0,_useQueries2.default)((0,_useBasename2.default)(createHistory))(options); return history; } module.exports = exports['default'];

10.match.js、applyRouterMiddleware.js、useRouterHistory.js

match.js、useRouterHistory.js作为工具函数;此外RouterContent.js也作为工具函数,对外提供接口,经用户装饰后,如输出WrappedRouterContent组件,向Router元素的props.render=function(props) {return React.createElement(WrappedRouterContent,props);},将改变Route元素下设定的待加载组件的渲染机制。具体用法缺省。。。

applyRouterMiddleware.js模块用于挂载中间件,用于装饰Route元素下设定的待挂载的Component元素,及RouterContent元素,获取RouterContent元素的创建函数,可作为Router元素的props.render传入,以影响待加载组件的绘制。中间件middleware的属性形式须含有renderRouteComponent、renderRouterContext方法。其中,renderRouteComponent(component,props)由props装饰Route元素下挂载的Component元素,参数component即Component元素(react-element形式);renderRouterContext(routerContent,renderProps)由renderProps封装RouterContent元素,参数routerContent即RouterContent元素。

match.js模块在服务器端异步渲染routes时使用,提供match( _ref={history,location},function(error,renderProps) )方法获取重定向路径数据redirectLocation、或_ref.location相应的renderProps={outer,matchContext,components},作为参数传入用户设置的回调函数中,完成页面重定向或组件重绘。具体用法缺省。。。

useRouterHistory.js模块提供useRouterHistory(createHistory)方法,用于装饰createHistory函数,location数据对象分离出query查询字符串序列化对象、basename基础路径。

match.js源码

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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 _Actions = require('history/lib/Actions'); // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); var _createMemoryHistory = require('./createMemoryHistory'); var _createMemoryHistory2 = _interoprequiredefault(_createMemoryHistory); // 创建transitionManager对象,用于监听、取消监听popstate、hashChange事件 var _createTransitionManager = require('./createTransitionManager'); var _createTransitionManager2 = _interoprequiredefault(_createTransitionManager); // 提供createRouterObject、assignRouterState方法 // createRouterObject(history,_ref)拷贝_ref的location、params、routes属性给router // 次参_ref通常是Router组件当前的state var _RouteUtils = require('./RouteUtils'); var _RouterUtils = require('./RouterUtils'); function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // obj的属性方法在keys中也有,不予拷贝 function _objectWithoutProperties(obj,i)) continue; target[i] = obj[i]; } return target; }; // 服务器端异步渲染routes使用,match({history,renderProps)) // 通过_ref.history、_ref.routes创建transitionManager对象,并执行transitionManager.match方法 // transitionManager.match方法中,获取_ref.location引起重定向路径数据redirectLocation、更迭的state数据nextState // 通过nextState={location,components}获得renderProps={router,components} // callback回调函数最终将获得参数redirectLocation、renderProps,用于页面重定向或组件渲染 function match(_ref,callback) { var history = _ref.history,routes = _ref.routes,location = _ref.location,options = _objectWithoutProperties(_ref,['history','routes','location']); !(history || location) ? process.env.NODE_ENV !== 'production' ? (0,'match needs a history or a location') : (0,_invariant2.default)(false) : void 0; history = history ? history : (0,_createMemoryHistory2.default)(options); var transitionManager = (0,_createTransitionManager2.default)(history,_RouteUtils.createRoutes)(routes)); if (location) { location = history.createLocation(location); } else { location = history.getCurrentLocation(); } transitionManager.match(location,nextState) { var renderProps = void 0; if (nextState) { var router = (0,nextState); renderProps = _extends({},{ router: router,matchContext: { transitionManager: transitionManager,router: router } }); } callback(error,redirectLocation && history.createLocation(redirectLocation,_Actions.REPLACE),renderProps); }); } exports.default = match; module.exports = exports['default'];

applyRouterMiddleware.js源码

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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 _react = require('react'); var _react2 = _interoprequiredefault(_react); // 负责渲染Router下子Route挂载的组件,由Router的state数据获取到激活的Route组件及其components待挂载的组件 // 通过底层的Route组件向上遍历父Route,创建待挂载渲染的props.component|components组件元素reactElement实现 var _RouterContext = require('./RouterContext'); var _RouterContext2 = _interoprequiredefault(_RouterContext); // 封装warning模块,目的是使含'deprecated'的警告文案只提示一次 var _routerWarning = require('./routerWarning'); var _routerWarning2 = _interoprequiredefault(_routerWarning); function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // middleware.renderRouteComponent(component,props) 由props装饰Route元素下挂载的Component元素 // middleware.renderRouterContext(routerContent,renderProps) 由renderProps封装RouterContent元素 // 使用中间件装饰Route下待挂载的Component元素,及装饰RouterContent元素 // 返回创建装饰RouterContent元素的函数,可作为Router元素的props.render属性传入,改变Component元素的渲染方式 exports.default = function () { for (var _len = arguments.length,middlewares = Array(_len),_key = 0; _key < _len; _key++) { middlewares[_key] = arguments[_key]; } // 中间件middleware须设置renderRouterContext、renderRouteComponent方法 if (process.env.NODE_ENV !== 'production') { middlewares.forEach(function (middleware,index) { process.env.NODE_ENV !== 'production' ? (0,_routerWarning2.default)(middleware.renderRouterContext || middleware.renderRouteComponent,'The middleware specified at index ' + index + ' does not appear to be ' + 'a valid React Router middleware.') : void 0; }); } var withContext = middlewares.map(function (middleware) { return middleware.renderRouterContext; }).filter(Boolean); var withComponent = middlewares.map(function (middleware) { return middleware.renderRouteComponent; }).filter(Boolean); // middleware.renderRouteComponent(component,props) 由props装饰Route元素下挂载的Component元素 // 返回用于创建Component元素的函数,该Component元素经middleware.renderRouteComponent封装后 // 返回函数function createElement(Component,props)将作为Route元素的props.createElement方法 var makeCreateElement = function makeCreateElement() { var baseCreateElement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _react.createElement; return function (Component,props) { return withComponent.reduceRight(function (prevIoUs,renderRouteComponent) { return renderRouteComponent(prevIoUs,baseCreateElement(Component,props)); }; }; // middleware.renderRouterContext(routerContent,renderProps) 由renderProps封装RouterContent元素 // 返回用于创建RouterContext元素的函数,该RouterContext元素middleware.renderRouterContext封装后 // 返回函数function createElement(RouterContext,renderProps)将作为Router元素的props.render方法 return function (renderProps) { return withContext.reduceRight(function (prevIoUs,renderRouterContext) { return renderRouterContext(prevIoUs,renderProps); },_react2.default.createElement(_RouterContext2.default,renderProps,{ createElement: makeCreateElement(renderProps.createElement) }))); }; }; module.exports = exports['default'];

useRouterHistory.js源码

@H_403_13@'use strict'; exports.__esModule = true; exports.default = useRouterHistory; // 装饰createHistory函数,操作location数据对象时分离query查询字符串对象,返回装饰函数 var _useQueries = require('history/lib/useQueries'); var _useQueries2 = _interoprequiredefault(_useQueries); // 装饰createHistory函数,操作location数据对象时分离basename,返回装饰函数 var _useBasename = require('history/lib/useBasename'); var _useBasename2 = _interoprequiredefault(_useBasename); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // 装饰createHistory函数,操作location数据对象时query查询字符串序列化对象、basename基础路径 function useRouterHistory(createHistory) { return function (options) { var history = (0,_useBasename2.default)(createHistory))(options); return history; }; } module.exports = exports['default'];

11.内置工具函数

AsyncUtils.js

AsyncUtils.js提供loopAsync、mapAsync函数

loopAsync(turns,work,callback)函数设定以高阶函数work(currentTurn,next,done)操作长度为turns的数组(纯数据或函数集);turns迭代最大次数,work(currentTurn++,done)迭代执行函数,callback回调

mapAsync(array,callback)函数以work函数遍历执行array的数组项item,work的第三个参数函数为每次遍历时执行的回调;该回调用获取callback的参数values,并判断遍历完成是否完成,完成后执行callback

@H_403_13@'use strict'; exports.__esModule = true; // loopAsync(turns,done)操作长度为turns的数组(纯数据或函数集) // turns迭代最大次数,work(currentTurn++,done)迭代执行函数,callback回调 // mapAsync(array,callback)函数以work函数遍历执行array的数组项item,work的第三个参数函数为每次遍历时执行的回调 // 该回调用获取callback的参数values,并判断遍历完成是否完成,完成后执行callback var _AsyncUtils = require('./AsyncUtils'); // isPromise(obj)判断obj是否promise对象 var _PromiseUtils = require('./PromiseUtils'); // 获取激活Route下挂载的组件,并执行回调 function getComponentsForRoute(nextState,callback) { if (route.component || route.components) { callback(null,route.component || route.components); return; } var getComponent = route.getComponent || route.getComponents; if (getComponent) { var componentReturn = getComponent.call(route,callback); if ((0,_PromiseUtils.isPromise)(componentReturn)) componentReturn.then(function (component) { return callback(null,component); },callback); } else { callback(); } } // getComponents(nextState,callback)获取激活路径下挂载的多个组件,并执行回调 function getComponents(nextState,callback) { (0,_AsyncUtils.mapAsync)(nextState.routes,function (route,index,callback) { getComponentsForRoute(nextState,callback); },callback); } exports.default = getComponents; module.exports = exports['default'];

computeChangedRoutes.js

computeChangedRoutes.js模块提供computeChangedRoutes方法

computeChangedRoutes(prevState,nextState)由前后两个路径数据prevState、nextState获取routes元素中参数待变更的changeRoutes、待移出的leaveRoutes、待进入的enterRoutes。

@H_403_13@'use strict'; exports.__esModule = true; // 通过histroy设定的路径格式获取真实路径的正则匹配规则,或获取真实路径的路径变量,或通过路径变量和路径格式获取真实路径 var _PatternUtils = require('./PatternUtils'); // 判断redux.store前后两个state数据prevState、nextState的params是否改变,实质是路径变量改变 function routeParamsChanged(route,prevState,nextState) { if (!route.path) return false; // 数组形式获取路径变量名 var paramNames = (0,_PatternUtils.getParamNames)(route.path); return paramNames.some(function (paramName) { return prevState.params[paramName] !== nextState.params[paramName]; }); } // 参数prevState、nextState为redux.store前后两个state数据,state.routes是Route组件的配置,数组形式 // 获取prevState待改变的route项leaveRoutes,nextState中保持与prevState相同的route项changeRoutes // nextState中与prevState相同的route项changeRoutes,或者route.path改变,或者state.params改变 function computeChangedRoutes(prevState,nextState) { var prevRoutes = prevState && prevState.routes;// 数组形式变更前的Route组件配置 var nextRoutes = nextState.routes;// 数组形式变更后的Route组件配置,route.path属性为路径 // prevState跳转为nextState时,存储prevRoutes中route.path或state.params待变更的route项 // prevState父route添加到leaveRoutes后,后续route全添加到leaveRoutes中 // 页面上即跳转到leaveRoutes[0]平级的Route组件中或leaveRoutes[0]的state.params作变更 var leaveRoutes = void 0,// prevState跳转为nextState时,nextState中和prevState中相同的route项 changeRoutes = void 0,// 存储prevRoutes跳转为nextRoutes时,nextState中和prevState中不同的route项,或者route.path改变,或者state.params改变 enterRoutes = void 0; if (prevRoutes) { (function () { var parentIsLeaving = false; leaveRoutes = prevRoutes.filter(function (route) { // 父route已作改变,子route全包含 if (parentIsLeaving) { return true; } else { var isLeaving = nextRoutes.indexOf(route) === -1 || routeParamsChanged(route,nextState); if (isLeaving) parentIsLeaving = true; return isLeaving; } }); leaveRoutes.reverse();// 反转为从子route到父route enterRoutes = []; changeRoutes = []; nextRoutes.forEach(function (route) { // nextRoutes所有的route不在prevRoutes中,route.path改变 // 页面上即为跳转到leaveRoutes[0]的平级Route组件后所有后续route var isNew = prevRoutes.indexOf(route) === -1; // nextRoutes所有的route也在leaveRoutes中,只可能leaveRoutes[0~i]的state.params作变更 var paramsChanged = leaveRoutes.indexOf(route) !== -1; if (isNew || paramsChanged){ enterRoutes.push(route); // nextRoutes所有的route在prevRoutes中,却不在leaveRoutes中 // 即nextRoutes和prevRoutes相同的route部分 }else{ changeRoutes.push(route); }; }); })(); } else { leaveRoutes = []; changeRoutes = []; enterRoutes = nextRoutes; } return { leaveRoutes: leaveRoutes,changeRoutes: changeRoutes,enterRoutes: enterRoutes }; } exports.default = computeChangedRoutes; module.exports = exports['default'];

ContextUtils.js

ContextUtils.js模块用于向下层组件提供监听Router元素的state变更,继而触发下层组件的setState方法执行并重绘。主要应用在Link、IndexLink、WithRouter(WrappedComponent)封装的WrappedComponent元素。

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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,WrappedComponent); } module.exports = exports['default'];

getComponents.js

getComponents.js提供getComponent方法

getComponents(nextState,callback)获取激活路径下挂载的多个组件,并执行回调。

@H_403_13@'use strict'; exports.__esModule = true; // loopAsync(turns,callback); } exports.default = getComponents; module.exports = exports['default'];

getRouteParams.js

getRouteParams.js提供getRouteParams方法

getRouteParams(route,params)由特定route及页面路径变量params获取该route下相关的变量信息。

@H_403_13@'use strict'; exports.__esModule = true; // 通过histroy设定的路径格式获取真实路径的正则匹配规则,或获取真实路径的路径变量,或通过路径变量和路径格式获取真实路径 var _PatternUtils = require('./PatternUtils'); // 通过route获取路径变量的键,再注入params相应键的值,意为当前route路径的变量 function getRouteParams(route,params) { var routeParams = {}; if (!route.path) return routeParams; (0,_PatternUtils.getParamNames)(route.path).forEach(function (p) { if (Object.prototype.hasOwnProperty.call(params,p)) { routeParams[p] = params[p]; } }); return routeParams; } exports.default = getRouteParams; module.exports = exports['default'];

InternalPropTypes.js

InternalPropTypes.js用于校验props。

@H_403_13@'use strict'; exports.__esModule = true; exports.routes = exports.route = exports.components = exports.component = exports.history = undefined; exports.falsy = falsy; var _react = require('react'); var func = _react.PropTypes.func,object = _react.PropTypes.object,arrayOf = _react.PropTypes.arrayOf,oneOfType = _react.PropTypes.oneOfType,element = _react.PropTypes.element,shape = _react.PropTypes.shape,string = _react.PropTypes.string; function falsy(props,propName,componentName) { if (props[propName]) return new Error('<' + componentName + '> should not have a "' + propName + '" prop'); } var history = exports.history = shape({ listen: func.isrequired,push: func.isrequired,replace: func.isrequired,go: func.isrequired,goBack: func.isrequired,goForward: func.isrequired }); var component = exports.component = oneOfType([func,string]); var components = exports.components = oneOfType([component,object]); var route = exports.route = oneOfType([object,element]); var routes = exports.routes = oneOfType([route,arrayOf(route)]);

PropTypes.js

@H_403_13@'use strict'; exports.__esModule = true; exports.locationShape = exports.routerShape = undefined; var _react = require('react'); var func = _react.PropTypes.func,string = _react.PropTypes.string; var routerShape = exports.routerShape = shape({ push: func.isrequired,goForward: func.isrequired,setRouteLeaveHook: func.isrequired,isActive: func.isrequired }); var locationShape = exports.locationShape = shape({ pathname: string.isrequired,search: string.isrequired,action: string.isrequired,key: string });

isActive.js

isActive.js模块提供isActive方法

isActive(_ref,params)用于校验特定路径数据_ref是否同当前页面路径pathname完全相等(indexOnly为真时);或者匹配激活组件设定的路由规则(indexOnly为否时)。

@H_403_13@'use strict'; exports.__esModule = true; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.default = isActive; // 通过histroy设定的路径格式获取真实路径的正则匹配规则,或获取真实路径的路径变量,或通过路径变量和路径格式获取真实路径 var _PatternUtils = require('./PatternUtils'); // 比较a,b值是否相等 function deepEqual(a,b) { if (a == b) return true; if (a == null || b == null) return false; if (Array.isArray(a)) { return Array.isArray(b) && a.length === b.length && a.every(function (item,index) { return deepEqual(item,b[index]); }); } if ((typeof a === 'undefined' ? 'undefined' : _typeof(a)) === 'object') { for (var p in a) { if (!Object.prototype.hasOwnProperty.call(a,p)) { continue; } if (a[p] === undefined) { if (b[p] !== undefined) { return false; } } else if (!Object.prototype.hasOwnProperty.call(b,p)) { return false; } else if (!deepEqual(a[p],b[p])) { return false; } } return true; } return String(a) === String(b); } // 比较pathname同当前路径currentPathname是否相同 function pathIsActive(pathname,currentPathname) { if (currentPathname.charAt(0) !== '/') { currentPathname = '/' + currentPathname; } if (pathname.charAt(pathname.length - 1) !== '/') { pathname += '/'; } if (currentPathname.charAt(currentPathname.length - 1) !== '/') { currentPathname += '/'; } return currentPathname === pathname; } // 判断路径数据pathname是否同当前页面路径下激活的routes、路径变量params相匹配 function routeIsActive(pathname,params) { var remainingPathname = pathname,paramNames = [],paramValues = []; for (var i = 0,len = routes.length; i < len; ++i) { var route = routes[i]; var pattern = route.path || ''; if (pattern.charAt(0) === '/') { remainingPathname = pathname; paramNames = []; paramValues = []; } if (remainingPathname !== null && pattern) { var matched = (0,_PatternUtils.matchPattern)(pattern,remainingPathname); if (matched) { remainingPathname = matched.remainingPathname; paramNames = [].concat(paramNames,matched.paramNames); paramValues = [].concat(paramValues,matched.paramValues); } else { remainingPathname = null; } if (remainingPathname === '') { return paramNames.every(function (paramName,index) { return String(paramValues[index]) === String(params[paramName]); }); } } } return false; } // 判断query路径变量是否同当前页面路径变量activeQuery匹配,query为null时,不需要匹配activeQuery function queryIsActive(query,activeQuery) { if (activeQuery == null) return query == null; if (query == null) return true; return deepEqual(query,activeQuery); } // 判断路径数据_ref同当前路径是否相同 // 参数_ref待校验的路径数据location // indexOnly为真值时路径pathname需要完全匹配,否则pathname匹配激活的route设下的路由规则即可 // 参数currentLocation,params当前页面相关数据 function isActive(_ref,params) { var pathname = _ref.pathname,query = _ref.query; if (currentLocation == null) return false; if (pathname.charAt(0) !== '/') { pathname = '/' + pathname; } if (!pathIsActive(pathname,currentLocation.pathname)) { if (indexOnly || !routeIsActive(pathname,params)) { return false; } } return queryIsActive(query,currentLocation.query); } module.exports = exports['default'];

matchRoutes.js

matchRoutes.js提供matchRoutes方法

matchRoutes(routes,callback,remainingPathname)用于获取获取当前路径下被激活的Route组件以及路径变量信息params,{routes,params}形式,并且将{routes,params}传入回调callback函数作为参数。

@H_403_13@'use strict'; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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 Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.default = matchRoutes; // loopAsync(turns,callback)函数以work函数遍历执行array的数组项item,work的第三个参数函数为每次遍历时执行的回调 // 该回调用获取callback的参数values,并判断遍历完成是否完成,完成后执行callback var _AsyncUtils = require('./AsyncUtils'); // isPromise(obj)判断obj是否promise对象 var _PromiseUtils = require('./PromiseUtils'); // 通过histroy设定的路径格式获取真实路径的正则匹配规则,或获取真实路径的路径变量,或通过路径变量和路径格式获取真实路径 var _PatternUtils = require('./PatternUtils'); // 封装warning模块,目的是使含'deprecated'的警告文案只提示一次 var _routerWarning = require('./routerWarning'); var _routerWarning2 = _interoprequiredefault(_routerWarning); // 提供一系列方法,目的是将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 var _RouteUtils = require('./RouteUtils'); function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // 同步或者异步方式获取childRoutes,通过route.childRoutes属性或getChildRoutes方法 function getChildRoutes(route,paramNames,paramValues,callback) { if (route.childRoutes) { return [null,route.childRoutes]; } if (!route.getChildRoutes) { return []; } var sync = true,result = void 0; var partialNextState = { location: location,params: createParams(paramNames,paramValues) }; var childRoutesReturn = route.getChildRoutes(partialNextState,childRoutes) { // _RouteUtils.createRoutes将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 childRoutes = !error && (0,_RouteUtils.createRoutes)(childRoutes); if (sync) { result = [error,childRoutes]; return; } callback(error,childRoutes); }); if ((0,_PromiseUtils.isPromise)(childRoutesReturn)) childRoutesReturn.then(function (childRoutes) { // _RouteUtils.createRoutes将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 return callback(null,_RouteUtils.createRoutes)(childRoutes)); },callback); sync = false; return result; // Might be undefined. } // IndexRoute处于路径激活状态,肯定是最末一个激活Route的子组件 // 激活的Route中添加相应的IndexRoute,意义还是获取待加载的组件 function getIndexRoute(route,callback) { if (route.indexRoute) { callback(null,route.indexRoute); } else if (route.getIndexRoute) {// 父Route以props配置书写getIndexRoute函数获取IndexRoute,供回调使用 var partialNextState = { location: location,paramValues) }; var indexRoutesReturn = route.getIndexRoute(partialNextState,indexRoute) { // _RouteUtils.createRoutes将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 callback(error,!error && (0,_RouteUtils.createRoutes)(indexRoute)[0]); }); // 支持异步,相关问题??? if ((0,_PromiseUtils.isPromise)(indexRoutesReturn)) indexRoutesReturn.then(function (indexRoute) { // _RouteUtils.createRoutes将Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 return callback(null,_RouteUtils.createRoutes)(indexRoute)[0]); },callback); } else if (route.childRoutes) { (function () { // Route组件没有设置props.path,获取其下IndexRoute组件,目的是获悉待加载的组件 var pathless = route.childRoutes.filter(function (childRoute) { return !childRoute.path; }); (0,_AsyncUtils.loopAsync)(pathless.length,function (index,done) { getIndexRoute(pathless[index],indexRoute) { if (error || indexRoute) { var routes = [pathless[index]].concat(Array.isArray(indexRoute) ? indexRoute : [indexRoute]); done(error,routes); } else { next(); } }); },function (err,routes) { callback(null,routes); }); })(); } else { callback(); } } // 合并路径变量对象 function assignParams(params,paramValues) { return paramNames.reduce(function (params,paramName,index) { var paramValue = paramValues && paramValues[index]; if (Array.isArray(params[paramName])) { params[paramName].push(paramValue); } else if (paramName in params) { params[paramName] = [params[paramName],paramValue]; } else { params[paramName] = paramValue; } return params; },params); } // 获取路径变量对象 function createParams(paramNames,paramValues) { return assignParams({},paramValues); } // 参数route是逐层遍历Route组件时该组件的配置项 // Route组件遍历通过反复调用matchRoutes函数实现,每次调用将遍历平级的Route组件 // 参数location当前页面路径数据 // 参数remainingPathname用于递归调用matchRouteDeep记录未被正则匹配的路径 // 参数paramNames、paramValues用于递归调用matchRouteDeep记录已获取的路径变量键及其值 // callback用于区别执行_AsyncUtils.loopAsync函数机制的done、next迭代函数 function matchRouteDeep(route,remainingPathname,callback) { var pattern = route.path || '';// route路径的正则匹配规则 // Router下第一层Route设置的path参数以"/"起始,第二层开始不以"/"起始 // 目的是使remainingPathname未匹配路径在第一层Route下为当前页面路径,第二层起始位当前页面路径剩余未匹配部分 // 通过matchRouteDeep函数remainingPathname传参实现 if (pattern.charAt(0) === '/') { remainingPathname = location.pathname;// 当前页面路径 paramNames = []; paramValues = []; } if (remainingPathname !== null && pattern) { // 获取route路径变量信息,混入paramNames、paramValues try { // _PatternUtils.matchPattern(pattern,remainingPathname),remainingPathname为实际页面路径未匹配部分 // 获取真实路径尾部未匹配的路径、路径变量名数组、路径变量值数组 var matched = (0,matched.paramValues); } else { remainingPathname = null; } } catch (error) { callback(error); } // 当前页面路径location数据已经被遍历的route匹配完毕,即当前路径下所有激活的Route // IndexRoute处于路径激活状态,肯定是最末一个激活Route的子组件 if (remainingPathname === '') { var _ret2 = function () { var match = { routes: [route],paramValues) }; // 激活的Route中添加相应的IndexRoute,意义还是获取待加载的组件 getIndexRoute(route,indexRoute) { if (error) { // Router组件下Route为单层形式,callback为createTransitionManager模块调用matchRoutes时设置 // Router组件下Route为多层形式,callback为onChildRoutes函数调用matchRoutes时设置 callback(error); } else { if (Array.isArray(indexRoute)) { var _match$routes; process.env.NODE_ENV !== 'production' ? (0,_routerWarning2.default)(indexRoute.every(function (route) { return !route.path; }),'Index routes should not have paths') : void 0; (_match$routes = match.routes).push.apply(_match$routes,indexRoute); } else if (indexRoute) { process.env.NODE_ENV !== 'production' ? (0,_routerWarning2.default)(!indexRoute.path,'Index routes should not have paths') : void 0; match.routes.push(indexRoute); } // Router组件下Route为单层形式,callback为createTransitionManager模块调用matchRoutes时设置 // Router组件下Route为多层形式,callback为onChildRoutes函数调用matchRoutes时设置 callback(null,match); } }); return { v: void 0 }; }(); if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v; } } // Router组件下Route为多层形式 // 通过调用matchRoutes函数遍历子Route组件的配置项,用以通过未匹配路径获取激活的Route,并获得match if (remainingPathname != null || route.childRoutes) { var onChildRoutes = function onChildRoutes(error,childRoutes) { if (error) { callback(error); } else if (childRoutes) { matchRoutes(childRoutes,match) { if (error) { callback(error); } else if (match) { // Router组件下Route为多层形式,match.routes已经通过_ret2添加了子route,再添加当前父route match.routes.unshift(route); // callback为createTransitionManager模块调用matchRoutes时设置 callback(null,match); } else { // callback为createTransitionManager模块调用matchRoutes时设置 callback(); } },paramValues); } else { callback(); } }; // getChildRoutes函数同步或者异步方式获取childRoutes,通过route.childRoutes属性或route.getChildRoutes方法 var result = getChildRoutes(route,onChildRoutes); if (result) { onChildRoutes.apply(undefined,result); } } else { callback(); } } // matchRoutes(routes,callback)外部调用, // 获取当前路径下被激活的Route组件以及路径变量信息params,{routes,params}传入回调callback函数作为参数 // matchRoutes(routes,remainingPathname)内部调用,遍历子Route组件,获取激活子Route信息 function matchRoutes(routes,remainingPathname) { var paramNames = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : []; var paramValues = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : []; if (remainingPathname === undefined) { if (location.pathname.charAt(0) !== '/') { location = _extends({},{ pathname: '/' + location.pathname }); } remainingPathname = location.pathname; } // _AsyncUtils.loopAsync(turns,done)操作长度为turns的数组(纯数据或函数集) // turns迭代最大次数,work(currentTurn++,done)迭代执行函数,callback回调 (0,_AsyncUtils.loopAsync)(routes.length,done) { matchRouteDeep(routes[index],match) { if (error || match) { done(error,match); } else { next(); } }); },callback); } module.exports = exports['default'];

PatternUtils.js 路径解析相关

PatternUtils.js提供compilePattern、matchPattern、getParamNames、getParams、formatPattern方法

compilePattern(pattern) 通过路由匹配规则pattern获取{pattern,regexpSource,tokens}正则匹配规则、路径变量、原始路径、拆分路径等。

matchPattern(pattern,pathname) 获取pathname下未符合路由规则的remainingPathname,数组形式的路径变量键与值,返回值为{remainingPathname,paramValue}形式。

getParamNames(pattern)数组形式获取路径变量的键。

getParams(pattern,pathname)以键值对获取路径变量。

formatPattern(pattern,params)将路径变量填入路由规则pattern中,获取实际路径输出

@H_403_13@'use strict'; exports.__esModule = true; exports.compilePattern = compilePattern; exports.matchPattern = matchPattern; exports.getParamNames = getParamNames; exports.getParams = getParams; exports.formatPattern = formatPattern; // node模块;invariant(condition,f替换报错模板字符串format,抛出错误 // _invariant2.default引用_invariant,即node模块invariant var _invariant = require('invariant'); var _invariant2 = _interoprequiredefault(_invariant); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // ".*+?^${}()|[]\"等特殊于正则的字符加"\" function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g,'\\$&'); } // 参数pattern为route中histroy设置的页面路径形式,书写形式为/path/:id形式,id为单页应用中的路径变量 // 通过路径获取正则规则和路径变量名,凭此得到当前页面的路径变量值 function _compilePattern(pattern) { var regexpSource = ''; var paramNames = []; var tokens = []; var match = void 0,lastIndex = 0,matcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|\*\*|\*|\(|\)/g; while (match = matcher.exec(pattern)) { if (match.index !== lastIndex) { tokens.push(pattern.slice(lastIndex,match.index)); regexpSource += escapeRegExp(pattern.slice(lastIndex,match.index)); } if (match[1]) { regexpSource += '([^/]+)'; paramNames.push(match[1]); } else if (match[0] === '**') { regexpSource += '(.*)'; paramNames.push('splat'); } else if (match[0] === '*') { regexpSource += '(.*?)'; paramNames.push('splat'); } else if (match[0] === '(') {// 非获取匹配,'(?:'及')?'可以满足或不满足匹配条件 regexpSource += '(?:'; } else if (match[0] === ')') { regexpSource += ')?'; } tokens.push(match[0]); lastIndex = matcher.lastIndex; } if (lastIndex !== pattern.length) { tokens.push(pattern.slice(lastIndex,pattern.length)); regexpSource += escapeRegExp(pattern.slice(lastIndex,pattern.length)); } return { pattern: pattern,// 完整原始路径 regexpSource: regexpSource,// 正则规则,([^/]+)或(.*)或(.*?)获取当前页面路径变量的值 paramNames: paramNames,// 路径变量名,(.*)或(.*?)匹配为"splat" tokens: tokens// 路径变量和非路径变量部分拆分为数组 }; } // 以对象形式存储解析为正则匹配规则的路径,键为路径名,值为正则匹配规则、路径变量、原始路径、拆分路径等 var CompiledPatternsCache = Object.create(null); // 通过histroy设置的页面路径形式获取正则匹配规则、路径变量、原始路径、拆分路径等,并存储到CompiledPatternsCache中 function compilePattern(pattern) { if (!CompiledPatternsCache[pattern]) CompiledPatternsCache[pattern] = _compilePattern(pattern); return CompiledPatternsCache[pattern]; } // 参数pattern为histroy设置的页面路径形式,pathname为实际页面路径 // 获取真实路径尾部未匹配的路径、路径变量名数组、路径变量值数组 function matchPattern(pattern,pathname) { if (pattern.charAt(0) !== '/') { pattern = '/' + pattern; } var _compilePattern2 = compilePattern(pattern),regexpSource = _compilePattern2.regexpSource,paramNames = _compilePattern2.paramNames,tokens = _compilePattern2.tokens; if (pattern.charAt(pattern.length - 1) !== '/') { regexpSource += '/?'; // Allow optional path separator at end. } // 参数pattern以"*"路径变量结尾,正则匹配规则添加"$",获取实际路径后所有内容 if (tokens[tokens.length - 1] === '*') { regexpSource += '$'; } var match = pathname.match(new RegExp('^' + regexpSource,'i')); if (match == null) { return null; } var matchedPath = match[0]; var remainingPathname = pathname.substr(matchedPath.length);// 后续未匹配正则的路径 if (remainingPathname) { // route中histroy设置的pattern以"/"结尾,匹配到真是路径的结尾 // route中histroy设置的pattern不以"/"结尾,不能匹配到真是路径的结尾 if (matchedPath.charAt(matchedPath.length - 1) !== '/') { return null; } // If there is a remaining pathname,treat the path separator as part of // the remaining pathname for properly continuing the match. remainingPathname = '/' + remainingPathname; } return { remainingPathname: remainingPathname,// 后续未匹配正则的路径 paramNames: paramNames,// 路径变量名,(.*)或(.*?)匹配为"splat" paramValues: match.slice(1).map(function (v) {// 路径变量对应的值 return v && decodeURIComponent(v);// 原生decodeURIComponent函数,url解码 }) }; } // 通过histroy设置的页面路径形式获取路径变量名 function getParamNames(pattern) { return compilePattern(pattern).paramNames; } // 参数pattern为histroy设置的页面路径形式,pathname为实际页面路径 // 以键值对形式获取路径变量 function getParams(pattern,pathname) { var match = matchPattern(pattern,pathname); if (!match) { return null; } var paramNames = match.paramNames,paramValues = match.paramValues; var params = {}; paramNames.forEach(function (paramName,index) { params[paramName] = paramValues[index]; }); return params; } // 参数pattern为histroy设置的页面路径形式,params键值对形式路径变量 // 获取真实路径输出 function formatPattern(pattern,params) { params = params || {}; var _compilePattern3 = compilePattern(pattern),tokens = _compilePattern3.tokens; var parenCount = 0,// 更新parenHistory记录()的个数 pathname = '',// 待拼接的路径 splatIndex = 0,// 通配符的个数 parenHistory = [];// 数组形式存储()间内容 var token = void 0,paramName = void 0,paramValue = void 0; for (var i = 0,len = tokens.length; i < len; ++i) { token = tokens[i]; if (token === '*' || token === '**') { paramValue = Array.isArray(params.splat) ? params.splat[splatIndex++] : params.splat; // pattern中路径格式通配符*不被()包裹,paramValue不能为空 !(paramValue != null || parenCount > 0) ? process.env.NODE_ENV !== 'production' ? (0,'Missing splat #%s for path "%s"',splatIndex,pattern) : (0,_invariant2.default)(false) : void 0; if (paramValue != null) pathname += encodeURI(paramValue);// 原生encodeURI函数,url编码 } else if (token === '(') { parenHistory[parenCount] = ''; parenCount += 1; } else if (token === ')') { var parenText = parenHistory.pop(); parenCount -= 1; // 多个(),将后一个")"、")"内容压入前一个 if (parenCount){ parenHistory[parenCount - 1] += parenText; // 所有起始的"("都找到匹配的")",使用parenHistory记录的()间内容,更新pathname }else{ pathname += parenText; } } else if (token.charAt(0) === ':') { paramName = token.substring(1); paramValue = params[paramName]; // pattern中路径格式:id不被()包裹,paramValue不能为空 !(paramValue != null || parenCount > 0) ? process.env.NODE_ENV !== 'production' ? (0,'Missing "%s" parameter for path "%s"',_invariant2.default)(false) : void 0; if (paramValue == null) { // pattern中路径格式:id被()包裹,paramValue无值,跳到相应的")"后 if (parenCount) { parenHistory[parenCount - 1] = ''; var curTokenIdx = tokens.indexOf(token);// ":id"所在序号 var tokensSubset = tokens.slice(curTokenIdx,tokens.length);// 以":id"起始的后续tokens var nextParenIdx = -1;// 用以获取")"在tokensSubset中的序号值 for (var _i = 0; _i < tokensSubset.length; _i++) { if (tokensSubset[_i] == ')') { nextParenIdx = _i; break; } } // "("缺少与之匹配的")",报错 !(nextParenIdx > 0) ? process.env.NODE_ENV !== 'production' ? (0,'Path "%s" is missing end paren at segment "%s"',pattern,tokensSubset.join('')) : (0,_invariant2.default)(false) : void 0; // 对应的”)”在tokens中的序号值,++i跳到")"后 i = curTokenIdx + nextParenIdx - 1; } // pattern中路径格式:id被()包裹,paramValue有值 } else if (parenCount){ parenHistory[parenCount - 1] += encodeURIComponent(paramValue); // pattern中路径格式:id不被()包裹,paramValue有值 }else{ pathname += encodeURIComponent(paramValue); } } else { if (parenCount){ parenHistory[parenCount - 1] += token; }else{ pathname += token; } } } // "("缺少与之匹配的")",报错 !(parenCount <= 0) ? process.env.NODE_ENV !== 'production' ? (0,'Path "%s" is missing end paren',pattern) : (0,_invariant2.default)(false) : void 0; return pathname.replace(/\/+/g,'/'); }

PromiseUtils.js

PromiseUtils.js模块提供isPromise方法

@H_403_13@'use strict'; exports.__esModule = true; exports.isPromise = isPromise; // isPromise(obj)判断obj是否promise对象 function isPromise(obj) { return obj && typeof obj.then === 'function'; }

routerWarning.js 错误提示

@H_403_13@'use strict'; exports.__esModule = true; exports.default = routerWarning; exports._resetWarned = _resetWarned; // node模块;warning(condition,args) 开发环境下,condition为否值时,使用args替换报错字符串模板format输出 // _warning2.default引用_warning,即node模块warning var _warning = require('warning'); var _warning2 = _interoprequiredefault(_warning); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var warned = {};// 存储已经提示过且不含'deprecated'的警告文案;不含'deprecated'的警告文案只提示一次 // 封装warning模块,目的是使含'deprecated'的警告文案只提示一次 function routerWarning(falseToWarn,message) { if (message.indexOf('deprecated') !== -1) { if (warned[message]) { return; } warned[message] = true; } message = '[react-router] ' + message; for (var _len = arguments.length,args = Array(_len > 2 ? _len - 2 : 0),_key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } _warning2.default.apply(undefined,[falseToWarn,message].concat(args)); } function _resetWarned() { warned = {}; }

RouterUtils.js

RouterUtils.js提供createRouterObject、assignRouterState方法

createRouterObject(history,state)创建router对象,用于@R_386_404@面、监听事件、获取当前页面路径数据等。

assignRouterState(router,_ref)更新router对象的路径数据,通常是页面跳转后、Router的state变更前即时更正为最新值。

@H_403_13@"use strict"; exports.__esModule = true; // 类似jquery.extend,将带靠背对象浅拷贝给目标对象 var _extends = Object.assign || 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,routes = _ref.routes; router.location = location; router.params = params; router.routes = routes; return router; }

RouteUtil.js 用于将JSX形式添加的Route元素转变为Router的props.routes数据,便于后续操作。

@H_403_13@'use strict'; exports.__esModule = true; var _extends = Object.assign || 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; }; exports.isReactChildren = isReactChildren; exports.createRouteFromReactElement = createRouteFromReactElement; exports.createRoutesFromReactChildren = createRoutesFromReactChildren; exports.createRoutes = createRoutes; var _react = require('react'); var _react2 = _interoprequiredefault(_react); // obj为history模块内建模块(函数),原样输出;否则将函数挂载在default方法上 function _interoprequiredefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // 校验元素是否reactElement function isValidChild(object) { return object == null || _react2.default.isValidElement(object); } // 校验单对象形式或数组形式的元素是否reactElement function isReactChildren(object) { return isValidChild(object) || Array.isArray(object) && object.every(isValidChild); } // 获取route元素的props function createRoute(defaultProps,props) { return _extends({},defaultProps,props); } // 通过route元素获取其props,作为router元素的props.routes|children配置 function createRouteFromReactElement(element) { var type = element.type; var route = createRoute(type.defaultProps,element.props); if (route.children) { // IndexRoute必然作为Route的子组件,同时Route也可能是Route的子组件 // IndexRoute情形,父route元素获得route.childRoutes属性的同时也得到route.indexRoute // route情形,父route元素获得route.childRoutes属性 var childRoutes = createRoutesFromReactChildren(route.children,route); if (childRoutes.length) route.childRoutes = childRoutes; delete route.children; } return route; } /** * import { Route,createRoutesFromReactChildren } from 'react-router' * * const routes = createRoutesFromReactChildren( * <Route component={App}> * <Route path="home" component={Dashboard}/> * <Route path="news" component={NewsFeed}/> * </Route> * ) */ // Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 function createRoutesFromReactChildren(children,parentRoute) { var routes = []; _react2.default.Children.forEach(children,function (element) { if (_react2.default.isValidElement(element)) { if (element.type.createRouteFromReactElement) { var route = element.type.createRouteFromReactElement(element,parentRoute); if (route) routes.push(route); } else { routes.push(createRouteFromReactElement(element)); } } }); return routes; } // Router中通过props.children添加的Route转化成props.routes形式,各route元素的props配置 // 参数routes为Router组件下第一层Route组件 function createRoutes(routes) { if (isReactChildren(routes)) { routes = createRoutesFromReactChildren(routes); } else if (routes && !Array.isArray(routes)) { routes = [routes]; } return routes; }

TransitionUtils.js 用于实现Route元素的props.onEnter | onLeave | onChange 方法的执行。

@H_403_13@'use strict'; exports.__esModule = true; exports.runEnterHooks = runEnterHooks; exports.runChangeHooks = runChangeHooks; exports.runLeaveHooks = runLeaveHooks; // loopAsync(turns,callback)函数以work函数遍历执行array的数组项item,work的第三个参数函数为每次遍历时执行的回调 // 该回调用获取callback的参数values,并判断遍历完成是否完成,完成后执行callback var _AsyncUtils = require('./AsyncUtils'); // 校验构造函数是否通过new关键字调用 function _classCallCheck(instance,Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // 添加或移除延迟执行的钩子函数,类似jquery的callback模块 var PendingHooks = function PendingHooks() { var _this = this; _classCallCheck(this,PendingHooks); this.hooks = []; this.add = function (hook) { return _this.hooks.push(hook); }; this.remove = function (hook) { return _this.hooks = _this.hooks.filter(function (h) { return h !== hook; }); }; this.has = function (hook) { return _this.hooks.indexOf(hook) !== -1; }; this.clear = function () { return _this.hooks = []; }; }; var enterHooks = new PendingHooks(); var changeHooks = new PendingHooks(); function createTransitionHook(hook,asyncArity,pendingHooks) { var isSync = hook.length < asyncArity;// hook为函数,asyncArity为真值时,isSync为真值 var transitionHook = function transitionHook() { for (var _len = arguments.length,args = Array(_len),_key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } hook.apply(route,args); if (isSync) { var callback = args[args.length - 1]; callback(); } }; pendingHooks.add(transitionHook); return transitionHook; } function getEnterHooks(routes) { return routes.reduce(function (hooks,route) { if (route.onEnter) hooks.push(createTransitionHook(route.onEnter,3,enterHooks)); return hooks; },[]); } // routes是当前路径下被激活的Route组件, function getChangeHooks(routes) { return routes.reduce(function (hooks,route) { if (route.onChange) hooks.push(createTransitionHook(route.onChange,4,changeHooks)); return hooks; },[]); } function runTransitionHooks(length,iter,callback) { if (!length) { callback(); return; } // Redirect元素处于激活状态,先通过Redirect元素的props.to重定向页面,再根据页面路径获取加载的组件 var redirectInfo = void 0; function replace(location) { redirectInfo = location; } (0,_AsyncUtils.loopAsync)(length,done) { iter(index,replace,function (error) { if (error || redirectInfo) { done(error,redirectInfo); } else { next(); } }); },callback); } // 路径改变时执行route.onEnter方法,异步在callback回调中处理 function runEnterHooks(routes,callback) { enterHooks.clear(); var hooks = getEnterHooks(routes); return runTransitionHooks(hooks.length,next) { var wrappedNext = function wrappedNext() { if (enterHooks.has(hooks[index])) { next(); enterHooks.remove(hooks[index]); } }; // nextState,replace作为route.onChange方法,wrappedNext为hooks的回调 hooks[index](nextState,wrappedNext); },callback); } // 路径改变时执行route.onChange方法,异步在callback回调中处理 function runChangeHooks(routes,callback) { // route.onChange方法为什么要用createTransitionHook函数进行封装,调用完成后又清空该transitionHook??? changeHooks.clear(); var hooks = getChangeHooks(routes); return runTransitionHooks(hooks.length,next) { var wrappedNext = function wrappedNext() { if (changeHooks.has(hooks[index])) { next(); changeHooks.remove(hooks[index]); } }; // state,replace作为route.onChange方法,wrappedNext为hooks的回调 hooks[index](state,callback); } // 离开Route时调用route.onLeave方法 function runLeaveHooks(routes,prevState) { for (var i = 0,len = routes.length; i < len; ++i) { if (routes[i].onLeave) routes[i].onLeave.call(routes[i],prevState); } }

猜你在找的React相关文章