1、React.Children
React.Children 是顶层API之一,为处理 this.props.children这个封闭的数据结构提供了有用的工具。
this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map(React.Children.forEach) 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。
2、DocumentTitle 动态改变页面title
react-document-title.js可以实现动态的修改页面的title,title属性一般会定义在route的配置中。将DocumentTitle包裹SPA的最外层元素。当路由发生变化时,也即DocumentTitle的属性props发生变化,会触发getPageTitle()方法被调用,动态获取对应路由的title(或者被定义为name)属性。
import DocumentTitle from 'react-document-title';
<DocumentTitle title={this.getPageTitle()}>
...
</DocumentTitle>
3、DrawerMenu 滑动侧边栏菜单
rc-drawer-menu.js可以实现侧边栏菜单的滑动,并支持相关事件处理。
import DrawerMenu from 'rc-drawer-menu';
<DrawerMenu
parent={null}
level={null}
iconChild={null}
open={!this.props.collapsed}
onMaskClick={() => {
props.onCollapse(true);
}}
width="256px"
>
<SiderMenu {...props} collapsed={this.props.collapsed} />
</DrawerMenu>
4、事件分发(订阅者模式)
应用场景:侧边栏滑动时,触发triggerResizeEvent方法,全局分发event,实际分发resize事件,在需要处理resize的页面监听event(resize),当事件触发时,this.resizeHandel将被执行;
@Debounce(600),利用装饰器,延迟600秒执行,函数防抖应用。
//事件触发
@Debounce(600)
triggerResizeEvent() {
const event = document.createEvent('HTMLEvents');
event.initEvent('resize', true, false);
//订阅者模式,事件分发
window.dispatchEvent(event);
}
//事件监听
window.addEventListener('resize', this.resizeHandel);
5、获取已经加载过的model
其中 app._model 含有namespace、state、reducers三个属性。其中namespace对应是model定义时的namespace属性
const modelNotExisted = (app, model) => {
!app._models.some(({namespace}) => {
return namespace === model.substring(model.lastIndexOf('/') + 1);
});
}
6、动态加载 — dva/dynamic
dynamic(app, models, component )
1. 第一个参数为挂载的对象,就是你要将这个router挂载到哪个实例上。
2. 第二个参数为这个router所需要的models。
3. 第三个参数为这个router的组件。
7、动态加载之封装 – dynamicWrapper
'/': {
component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
},
在common/router.js中,对应的路由都有以上形式。dynamicWrapper的功能主要有三点:
1. 将对应路由挂在dva实例上。也即将path=’/'的路由信息挂载在app实例上;
2. 加载当前路由依赖的model数据。也即path=’/'的路由依赖数据model(user、login);
3. 将对应的component生成UI展示,也即() => import(’…/layouts/BasicLayout’),将渲染BasicLayout。此处利用了webpack的动态模块加载。
下边具体分析dynamicWrapper方法是如何上线上述功能。具体代码如下:
const dynamicWrapper = (app, models, component) => {
// () => require('module')
// transformed by babel-plugin-dynamic-import-node-sync
if (component.toString().indexOf('.then(') < 0) {
models.forEach(model => {
if (modelNotExisted(app, model)) {
// eslint-disable-next-line
app.model(require(`../models/${model}`).default);
}
});
return props => {
if (!routerDataCache) {
routerDataCache = getRouterData(app);
}
return createElement(component().default, {
...props,
routerData: routerDataCache,
});
};
}
// () => import('module')
return dynamic({
app,
models: () =>
models.filter(model => modelNotExisted(app, model)).map(m => import(`../models/${m}.js`)),
// add routerData prop
component: () => {
if (!routerDataCache) {
routerDataCache = getRouterData(app);
}
return component().then(raw => {
const Component = raw.default || raw;
return props =>
createElement(Component, {
...props,
routerData: routerDataCache,
});
});
},
});
};
由以上代码可知,首先判断是require方法引入文件,还是import方法引入文件。两种情况下都会判断当前model是否已经加载。如未加载,则通过app实例注册/models/路径下对应的文件。两个return本质上返回的是一直。都返回如下部分:
return props =>
createElement(Component, {
...props,
routerData: routerDataCache,
});
});
通过调用React原生方法createElement方法生成Component组件,并把routerData等属性注入到组件中,同时接受外部props。所有的路由组件,都是作为Route组件的子组件,也就是所有的路由组件都会被注入Route组件的基本属性props(match、location、history),不管是通过render属性还是component属性。同时注入了routerData数据。
8、pathToRegexp — 路径转换
import pathToRegexp from 'path-to-regexp';
const pathRegexp = pathToRegexp(path);
使用path-to-regexp,我们可以在路径字符串中使用正则。如/:foo*/:bar?、/icon-:foo(\d+).png等。/foo/:bar中的/为分隔符,把多个匹配模式分隔开,这里就分成foo和:bar。像foo这种不带:前缀的,我们请求的路径需要和它完全匹配,而:bar这种,叫命名参数,就像个函数形参,可以传递任何请求路径字串给它
- * 表示我这个命名参数:bar可以接收随意个匹配模式,就好像参数数组长度[0,+∞)
- + 表示命名参数可以接收至少一个匹配模式,一个都没就匹配失败,[1,+∞)
- ? 表示命名参数可以接收0个或1个匹配模式,多个失败,[0,1]
参考 PocketLibs(2)—— 请求相关 path-to-regexp
9、获取URL参数
const urlParams = new URL(window.location.href);
const redirect = urlParams.searchParams.get('redirect');
- 当url为:http://localhost:8000/?redirect=/result/success时, 可以获得redirect为’/result/success’
- 当url为:http://localhost:8000/#/?redirect=/result/success, redirect为null (被认为是hash参数)
- 如需获取hash参数,使用location.hash 获取之后在解析
10、window.history.replaceState
HTML5为history对象添加了两个新方法,history.pushState()和history.replaceState(),用来在浏览历史中添加和修改记录。
不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应。pushState向history中添加记录(后退可见内容),replaceState修改记录(后退不可见上次内容)
history.replaceState方法的参数与pushState方法一模一样,接受三个参数,依次为:
state:一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。
title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。
url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
如果想要插入一个跨域的网址,导致报错。这样设计的目的是,防止恶意代码让用户以为他们是在另一个网站上。
上一篇:ant design pro 代码学习(四) ----- 数据mock
下一篇:ant design pro 代码学习(六) ----- 知识点总结2
参考:https://blog.csdn.net/u012028371/article/details/67636395