# Layout Basic 主框架布局

- 来源：[E10 UI 组件库](https://www.e-cology.com.cn/ui/root-layout/freepass)
- 平台：PC
- 维护者：揭志胜
- Issue：http://gitlab.ecology10.cn/FRONTEND/weapp-ui/-/issues?state=all&search=[RootLayout]

## 代码演示

### 基本使用

主框架中使用的布局组件

```jsx
import React, { FC } from 'react';
import { withRouter } from 'react-router-dom';

import { classUseMemo } from '@weapp/utils';
import { AnyObj, constants, Button, Empty, Icon, RootLayout, rootLayoutUtils, RootLayoutMenuData } from '@weapp/ui';
import { formatParentPath } from '../../../../utils';

const prefixCls = `${constants.uiPcClsPrefix}-demo-root-layout`;

const ModuleWrapDemo: FC<any> = (props) => {
  const { renderConfig, children } = props;
  if (renderConfig?.errorType === '404') {
    return (
      <Empty
       
        title={'404'}
        className={`${prefixCls}-empty`}
        description='暂无显示内容'
        image={
          <Icon
           
            style={{ width: 100, height: 100 }}
            name={'Icon-empty-file'}
          />
        }
      />
    );
  }
  // 如果不需要拦截渲染，直接返回 children 即可
  return children;
}

class TestComponent extends React.Component<any, any> {
  render() {
    return (
      <h3>Test Component</h3>
    );
  }
}

class LayoutDemo extends React.Component<any, any> {

  constructor(props: any) {
    super(props);
    this.state = {
      layout: 1,
    }
  }

  showCorsComponent = () => {
    const parentPath = formatParentPath(this.props as any);
    rootLayoutUtils.doAction('pushRoute', { path: `${parentPath}/corsComponent` });
  }

  showIframe = () => {
    const parentPath = formatParentPath(this.props as any);
    rootLayoutUtils.doAction('pushRoute', { path: `${parentPath}/iframe` });
  }

  showComponent = () => {
    const parentPath = formatParentPath(this.props as any);
    rootLayoutUtils.doAction('pushRoute', { path: `${parentPath}/component` });
  }

  showMicroApp = () => {
    const parentPath = formatParentPath(this.props as any);
    rootLayoutUtils.doAction('pushRoute', { path: `${parentPath}/microApp` });
  }

  changeLayout1 = () => this.setState({ layout: 1 });
  changeLayout2 = () => this.setState({ layout: 2 });
  changeLayout3 = () => this.setState({ layout: 3 });
  changeLayout4 = () => this.setState({ layout: 4 });
  changeLayout5 = () => this.setState({ layout: 5 });
  changeLayout6 = () => this.setState({ layout: 6 });

  handleInit = () => {
    console.log('初始化钩子函数');
    // 可以返回需要加载的插件
    return [
      { id: 'iframe', enablePlugin: true, renderType: 'iframe', iframeConfig: { src: 'https://www.baidu.com' } },
      { id: 'component2', enablePlugin: true, renderType: 'component', componentType: TestComponent },
    ] as RootLayoutMenuData[];
  }

  render() {
    const { layout } = this.state;
    const navCom = (
      <span>Navigation</span>
    );
    const asideCom = (
      <span>Aside</span>
    );
    const parentPath = formatParentPath(this.props as any);

    const menuData: RootLayoutMenuData[] = classUseMemo('menuData', this, () => ([
      { id: 'corsComponent', path: `${parentPath}/corsComponent`, renderType: 'corsComponent', corsComponentProps: { app: '@weapp/demo', compName: 'ViewDialog', visible: true } },
      { id: 'iframe', path: `${parentPath}/iframe`, renderType: 'iframe', iframeConfig: { src: 'https://www.baidu.com' } },
      { id: 'component', path: `${parentPath}/component`, renderType: 'component', componentType: TestComponent },
      { id: 'microApp', path: `${parentPath}/microApp`, renderType: 'microApp', microAppProps: { name: 'eteams', url: 'https://eteams.cn/index' } },
    ]), []);

    const navigationProps = classUseMemo('navigationProps', this, () => {
      let newProps: any = {
        className: "box"
      };
      switch(layout) {
        case 1:
        case 2:
          newProps = {
            ...newProps,
            type: 'header',
            outer: true,
          };
          break;
        case 3:
          newProps = {
            ...newProps,
            type: 'header',
            outer: false,
          }
          break;
        case 4:
          newProps = {
            ...newProps,
            type: 'side',
            outer: true,
            rigth: false,
          }
          break;
        default:
          break;
      }
      return newProps;
    }, [layout]);

    const asideProps = classUseMemo('asideProps', this, () => {
      let newProps: any = {
        className: "box"
      };
      switch(layout) {
        case 1:
        case 4:
        case 5:
          newProps = {
            ...newProps,
            type: 'side',
            outer: false,
            right: false,
          };
          break;
        case 2:
          newProps = {
            ...newProps,
            type: 'header',
            outer: false,
            right: false,
            width: undefined,
          }
          break;
        case 6:
          newProps = {
            ...newProps,
            type: 'side',
            outer: false,
            right: true,
          }
          break;
        default:
          break;
      }
      return newProps;
    }, [layout]);

    const contentProps = classUseMemo('contentProps', this, () => ({
      className: "box"
    }), []);

    return (
      <div className={prefixCls}>
        <p>
          <h3> menu 功能测试 </h3>
          <Button onClick={this.showCorsComponent}>
            显示 corsComponent
          </Button>
          &nbsp;
          <Button onClick={this.showIframe}>
            显示 iframe
          </Button>
          &nbsp;
          <Button onClick={this.showComponent}>
            显示 component
          </Button>
          &nbsp;
          <Button onClick={this.showMicroApp}>
            显示 MircoApp
          </Button>
        </p>
        <p>
          <h3> 布局切换 </h3>
          <h5>顶部菜单</h5>
          <Button onClick={this.changeLayout1}>
            顶部菜单 + 左侧菜单
          </Button>
          &nbsp;
          <Button onClick={this.changeLayout2}>
            顶部菜单 + 二级菜单
          </Button>
          &nbsp;
          <Button onClick={this.changeLayout3}>
            只显示顶部菜单
          </Button>
          <h5>侧边菜单</h5>
          <Button onClick={this.changeLayout4}>
            左侧菜单 + 二级菜单
          </Button>
          &nbsp;
          <Button onClick={this.changeLayout5}>
            只显示左侧菜单
          </Button>
          &nbsp;
          <Button onClick={this.changeLayout6}>
            只显示右侧菜单
          </Button>
        </p>
        <RootLayout
         
          menu={menuData}
          navigation={(layout === 5 || layout === 6) ? undefined : navCom}
          navigationProps={navigationProps}
          aside={layout === 3 ? undefined : asideCom}
          asideProps={asideProps}
          contentProps={contentProps}
          // onInit={this.handleInit}
          ModuleWrapComponent={ModuleWrapDemo}
        />
      </div>
    )
  }
}

export default withRouter(LayoutDemo);
```

## API

### 参数说明如下：

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| menu | 菜单配置数据 | AnyObj | F | - |
| navigation | 顶部菜单 | ReactNode | F | - |
| navigationProps | 顶部菜单布局Box属性 | LayoutBoxProps | F | - |
| aside | 侧边栏 | ReactNode | F | - |
| asideProps | 侧边栏布局Box属性 | LayoutBoxProps | F | - |
| contentProps | 内容布局Box属性 | LayoutBoxProps | F | - |
| onInit | 初始化加载回调函数 | () => void | F | - |
| ModuleWrapComponent | 内容区域容器组件 | React.ComponentType | F | - |
| moduleName | 当前使用模块名称，默认为`@weapp/layout` | String | F | '@weapp/layout' |
### 渲染配置说明

- corsComponent 异步调用标准模块组件
- ecodeComponent 异步调用ecode中的组件
- iframe 加载iframe
- component 直接传入渲染组件

具体渲染配置说明可以[参考文档](https://weapp.eteams.cn/sp/techdoc/doc/748718039403053057)

### 动作执行配置说明

- 'pushRoute' // push 路由
- 'openLink' // open 新页签
- 'openHref' // 直接单签页面跳转地址
- 'doRequest' // 需要发送一个接口给后台
- 'refresh' // 刷新页面
- 'saveLocalStorage' // 填写开关标识，比如默认 ecode 是发布的，往限定的TEAMS 对象的指定字段和限定的 localStorage 等填写标识
- 'callFunction' // 打开弹框 Dialog（需要提前做好方法的，和装载指定组件一样，要配置数据配置调用指定规范方法名）
