ant design pro 代码学习(五) ----- 知识点总结1

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。

  参考:对React children 的深入理解

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, model, component )
1. 第一个参数为挂载的对象,就是你要将这个router挂载到哪个实例上。
2. 第二个参数为这个router所需要的model。
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');

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


猜你喜欢

转载自blog.csdn.net/zcs425171513/article/details/80914668