
# 布局

页面级整体布局。

## 布局规则

一级导航项偏左靠近 logo 放置，辅助菜单偏右放置。

- 顶部导航（大部分系统）：一级导航高度 `64px`，二级导航 `48px`。
- 顶部导航（展示类页面）：一级导航高度 `80px`，二级导航 `56px`。
- 顶部导航高度的范围计算公式为：`48+8n`。
- 侧边导航宽度的范围计算公式：`200+8n`。

## 组件概述

- `Layout`：布局容器，其下可嵌套 `Header` `Sider` `Content` `Footer` 或 `Layout` 本身，可以放在任何父容器中。
- `Header`：顶部布局，自带默认样式，其下可嵌套任何元素，只能放在 `Layout` 中。
- `Sider`：侧边栏，自带默认样式及基本功能，其下可嵌套任何元素，只能放在 `Layout` 中。
- `Content`：内容部分，自带默认样式，其下可嵌套任何元素，只能放在 `Layout` 中。
- `Footer`：底部布局，自带默认样式，其下可嵌套任何元素，只能放在 `Layout` 中。

> 注意：采用 flex 布局实现，请注意[浏览器兼容性](http://caniuse.com/#search=flex)问题。

## 简单使用

```js
<Layout>
  <Header>header</Header>
  <Layout>
    <Sider>left sidebar</Sider>
    <Content>main content</Content>
    <Sider>right sidebar</Sider>
  </Layout>
  <Footer>footer</Footer>
</Layout>
```


## 案例演示

### Layout 基本用法

---demo
```js
import { Layout } from 'amos-framework';

const { Header, Footer, Sider, Content } = Layout;

const styles = {
  layoutStyle: {
    marginBottom: '48px'
  },
  headerStyle: {
    background: '#373e40',
    color: ' #fff'
  },
  contentStyle: {
    background: '#82abba',
    color: 'black',
    minHeight: '120px',
    lineHeight: '120px'
  },
  footerStyle: {
    background: '#a2b4ba',
    color: 'black',
    lineHeight: 1.5
  },
  sliderStyle: {
    background: '#00b0f0',
    color: '#fff',
    lineHeight: '120px'
  }
};

const Basic = props => {
  return (
    <div>
      <Layout style={styles.layoutStyle}>
        <Header style={styles.headerStyle}>Header</Header>
        <Content style={styles.contentStyle}>Content</Content>
        <Footer style={styles.footerStyle}>Footer</Footer>
      </Layout>

      <Layout style={styles.layoutStyle}>
        <Header style={styles.headerStyle}>Header</Header>
        <Layout>
          <Sider style={styles.sliderStyle}>Sider</Sider>
          <Content style={styles.contentStyle}>Content</Content>
        </Layout>
        <Footer style={styles.footerStyle}>Footer</Footer>
      </Layout>

      <Layout style={styles.layoutStyle}>
        <Header style={styles.headerStyle}>Header</Header>
        <Layout>
          <Content style={styles.contentStyle}>Content</Content>
          <Sider style={styles.sliderStyle}>Sider</Sider>
        </Layout>
        <Footer style={styles.footerStyle}>Footer</Footer>
      </Layout>

      <Layout style={styles.layoutStyle}>
        <Sider style={styles.sliderStyle}>Sider</Sider>
        <Layout>
          <Header style={styles.headerStyle}>Header</Header>
          <Content style={styles.contentStyle}>Content</Content>
          <Footer style={styles.footerStyle}>Footer</Footer>
        </Layout>
      </Layout>
    </div>
  );
};

ReactDOM.render(<Basic />, _react_runner_);
```
---demoend

### Layout 上中下结构

---demo
```js
import { Layout } from 'amos-framework';

const { Header, Footer, Content } = Layout;

const styles = {
  logo: {
    width: '120px',
    height: '31px',
    background: 'rgba(255,255,255,.2)',
    margin: '16px 24px 16px 0',
    float: 'left'
  },
  header: {
    background: 'black'
  }
};

const TopMidBotom = props => {
  return (
    <Layout className="layout">
      <Header style={styles.header}>
        <div style={styles.logo} />
        <Nav
          direction="horizontal"
          style={{ lineHeight: '64px', background: 'black' }}
        >
          <NavItem key="1" title="首页" />
          <NavItem key="2" title="用户中心" />
          <NavItem key="3" title="配置" />
        </Nav>
      </Header>
      <Content style={{ padding: '0 50px' }}>
        <Breadcrumb style={{ margin: '12px 0' }}>
          <Breadcrumb.Item>Home</Breadcrumb.Item>
          <Breadcrumb.Item>List</Breadcrumb.Item>
          <Breadcrumb.Item>App</Breadcrumb.Item>
        </Breadcrumb>
        <div style={{ background: '#fff', padding: 24, minHeight: 500 }}>Content</div>
      </Content>
      <Footer style={{ textAlign: 'center' }}>
        @copyright AMOS
      </Footer>
    </Layout>
  );
};

ReactDOM.render(<TopMidBotom />, _react_runner_);
```
---demoend

### Layout 侧边布局(可控)

---demo
```js
import { Layout, Nav, NavItem, Breadcrumb } from 'amos-framework';

const { Sider, Footer, Content, Header } = Layout;

const styles = {
  logo: {
    height: '32px',
    background: '#333',
    borderRadius: '6px',
    margin: '16px'
  },
  header: {
    background: '#fff',
    padding: 0
  }
};

const SiderLayout = props => {
  const { folded, toggleSlider } = props;
  return (
    <Layout>
      <Sider
        foldable
        folded={folded}
        foldedWidth={90}
        onFolded={toggleSlider}
      >
        <div style={styles.logo} />
        <Nav>
          <NavItem key="1" title="首页" />
          <NavItem key="2" title="用户中心" />
          <NavItem key="3" title="配置" />
        </Nav>
      </Sider>
      <Layout>
        <Header style={styles.header} />
        <Content style={{ margin: '0 16px' }}>
          <Breadcrumb style={{ margin: '12px 0' }}>
            <Breadcrumb.Item>User</Breadcrumb.Item>
            <Breadcrumb.Item>Bill</Breadcrumb.Item>
          </Breadcrumb>
          <div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
            Bill is a cat.
          </div>
        </Content>
        <Footer style={{ textAlign: 'center' }}>
          @copyright AMOS
        </Footer>
      </Layout>
    </Layout>
  );
};

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      folded: false
    };
  }

  toggleSlider = (folded) => {
    this.setState({
      folded
    });
  }

  render() {
    return <SiderLayout folded={this.state.folded} toggleSlider={this.toggleSlider} />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### Layout 自定义trigger

---demo
```js
import { Layout, Nav, NavItem, Icon } from 'amos-framework';

const { Header, Sider, Content } = Layout;

const styles = {
  logo: {
    height: '32px',
    background: '#333',
    borderRadius: '6px',
    margin: '16px'
  },
  header: {
    background: '#CCC'
  },
  trigger: {
    fontSize: '18px',
    lineHeight: '64px',
    padding: '0 16px',
    cursor: 'pointer',
    transition: 'color 0.3s'
  }
};

const CustomTrigger = props => {
  const { folded, toggleSlider } = props;
  return (
    <div>
      <Layout>
        <Sider
          trigger={null}
          foldable
          folded={folded}
        >
          <div style={styles.logo} />
          <Nav>
            <NavItem key="1" title="首页" />
            <NavItem key="2" title="用户中心" />
            <NavItem key="3" title="配置" />
          </Nav>
        </Sider>
        <Layout>
          <Header style={{ background: '#fff', padding: 0 }}>
            <Icon
              style={styles.trigger}
              icon={folded ? 'right' : 'left'}
              onClick={() => toggleSlider(!folded)}
            />
          </Header>
          <Content style={{ margin: '24px 16px', padding: 24, background: '#fff', minHeight: 500 }}>
            Content
          </Content>
        </Layout>
      </Layout>
    </div>
  );
};

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      folded: false
    };
  }

  toggleSlider = (folded) => {
    this.setState({
      folded
    });
  }

  render() {
    return <CustomTrigger folded={this.state.folded} toggleSlider={this.toggleSlider} />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### Layout 顶部-侧边栏 上下

---demo
```js
import { Layout, Nav, NavItem, Breadcrumb } from 'amos-framework';

const { Header, Footer, Content, Sider } = Layout;

const styles = {
  logo: {
    width: '120px',
    height: '31px',
    background: 'rgba(255,255,255,.2)',
    margin: '16px 24px 16px 0',
    float: 'left'
  },
  header: {
    background: 'black'
  }
};


/**
 * 顶部-侧边栏 上下
 * @param {object} props
 */
const AllNoraml = props => {
  return (
    <Layout>
      <Header style={styles.header}>
        <div style={styles.logo} />
        <Nav
          direction="horizontal"
          style={{ lineHeight: '64px', background: 'black' }}
        >
          <NavItem key="1" title="首页" />
          <NavItem key="2" title="用户中心" />
          <NavItem key="3" title="配置" />
        </Nav>
      </Header>
      <Layout>
        <Sider width={200} style={{ background: '#fff' }}>
          <Nav>
            <NavItem key="1" title="首页" />
            <NavItem key="2" title="用户中心" />
            <NavItem key="3" title="配置" />
          </Nav>
        </Sider>
        <Layout style={{ padding: '0 24px 24px' }}>
          <Breadcrumb style={{ margin: '12px 0' }}>
            <Breadcrumb.Item>Home</Breadcrumb.Item>
            <Breadcrumb.Item>List</Breadcrumb.Item>
            <Breadcrumb.Item>App</Breadcrumb.Item>
          </Breadcrumb>
          <Content style={{ background: '#fff', padding: 24, margin: 0, minHeight: 500 }}>
            Content
          </Content>
        </Layout>
      </Layout>
    </Layout>
  );
};

ReactDOM.render(<AllNoraml />, _react_runner_);
```
---demoend

### Layout 顶部-侧边栏 上下 footer

---demo
```js
import { Layout, Nav, NavItem, Breadcrumb } from 'amos-framework';

const { Header, Footer, Content, Sider } = Layout;


const styles = {
  logo: {
    width: '120px',
    height: '31px',
    background: 'rgba(255,255,255,.2)',
    margin: '16px 24px 16px 0',
    float: 'left'
  },
  header: {
    background: 'black'
  }
};

/**
 * 顶部-侧边栏 上下 footer
 * @param {object} props
 */
const AllNoraml1 = props => {
  return (
    <Layout>
      <Header style={styles.header}>
        <div style={styles.logo} />
        <Nav
          direction="horizontal"
          style={{ lineHeight: '64px', background: 'black' }}
        >
          <NavItem key="1" title="首页" />
          <NavItem key="2" title="用户中心" />
          <NavItem key="3" title="配置" />
        </Nav>
      </Header>
      <Content style={{ padding: '0 50px' }}>
        <Breadcrumb style={{ margin: '12px 0' }}>
          <Breadcrumb.Item>Home</Breadcrumb.Item>
          <Breadcrumb.Item>List</Breadcrumb.Item>
          <Breadcrumb.Item>App</Breadcrumb.Item>
        </Breadcrumb>
        <Layout style={{ padding: '24px 0', background: '#fff' }}>
          <Sider width={200} style={{ background: '#fff' }}>
            <Nav>
              <NavItem key="1" title="首页" />
              <NavItem key="2" title="用户中心" />
              <NavItem key="3" title="配置" />
            </Nav>
          </Sider>
          <Content style={{ padding: '0 24px', minHeight: 500 }}>
            Content
          </Content>
        </Layout>
      </Content>
      <Footer style={{ textAlign: 'center' }}>
        @copyright AMOS
      </Footer>
    </Layout>
  );
};

ReactDOM.render(<AllNoraml1 />, _react_runner_);
```
---demoend

### Layout 固定头部

---demo
```js
import { Layout, Nav, NavItem, Breadcrumb } from 'amos-framework';

const { Header, Footer, Content, Sider } = Layout;

const styles = {
  logo: {
    width: '120px',
    height: '31px',
    background: 'rgba(255,255,255,.2)',
    margin: '16px 24px 16px 0',
    float: 'left'
  },
  header: {
    background: 'black',
    position: 'fixed',
    width: '100%'
  }
};

/**
 * 固定头部
 * @param {object} props
 */
const Fixed = props => {
  return (
    <Layout>
      <Header style={styles.header}>
        <div style={styles.logo} />
        <Nav
          direction="horizontal"
          style={{ lineHeight: '64px', background: 'black' }}
        >
          <NavItem key="1" title="首页" />
          <NavItem key="2" title="用户中心" />
          <NavItem key="3" title="配置" />
        </Nav>
      </Header>
      <Content style={{ padding: '0 50px', marginTop: 64 }}>
        <Breadcrumb style={{ margin: '12px 0' }}>
          <Breadcrumb.Item>Home</Breadcrumb.Item>
          <Breadcrumb.Item>List</Breadcrumb.Item>
          <Breadcrumb.Item>App</Breadcrumb.Item>
        </Breadcrumb>
        <div style={{ background: '#fff', padding: 24, minHeight: 380 }}>Content</div>
      </Content>
      <Footer style={{ textAlign: 'center' }}>
        @copyright AMOS
      </Footer>
    </Layout>
  );
};

ReactDOM.render(<Fixed />, _react_runner_);
```
---demoend

### Layout 固定侧边栏

---demo
```js
import { Layout, Nav, NavItem, Breadcrumb } from 'amos-framework';

const { Header, Footer, Content, Sider } = Layout;

const styles = {
  logo: {
    width: '100%',
    height: '31px',
    background: 'rgba(255,255,255,.2)',
    margin: '16px 0'
  },
  header: {
    background: '#404040',
    padding: 0
  }
};

/**
 * 固定侧边栏
 * @param {object} props
 */
const FixedSider = props => {
  // 设置 transform 确保 内部 Sider fixed 相对于父节点
  return (
    <Layout style={{ transform: 'scale(1)' }}>
      <Sider style={{ overflow: 'auto', height: '100%', position: 'fixed', left: 0 }} contentStyle={{ overflow: 'hidden', height: '100%' }}>
        <div style={styles.logo} />
        <Nav>
          <NavItem key="1" title="首页" />
          <NavItem key="2" title="用户中心" />
          <NavItem key="3" title="配置" />
        </Nav>
      </Sider>
      <Layout style={{ marginLeft: 200 }}>
        <Header style={styles.header} />
        <Content style={{ margin: '24px 16px 0', overflow: 'initial' }}>
          <div style={{ padding: 24, background: '#fff', textAlign: 'center' }}>
            ...
            <br />
            <br />...<br />...<br />...<br />
            long
            <br />...<br />...<br />...<br />...<br />...<br />...
            <br />...<br />...<br />...<br />...<br />...<br />...
            <br />...<br />...<br />...<br />...<br />...<br />
            content
          </div>
        </Content>
        <Footer style={{ textAlign: 'center' }}>
          @copyright AMOS
        </Footer>
      </Layout>
    </Layout>
  );
};

ReactDOM.render(<FixedSider />, _react_runner_);
```
---demoend

### Layout 响应式

---demo
```js
import { Layout, Nav, NavItem } from 'amos-framework';

const { Header, Footer, Content, Sider } = Layout;

const styles = {
  logo: {
    width: '120px',
    height: '31px',
    background: 'rgba(255,255,255,.2)',
    margin: '16px 24px 16px 0'
  },
  header: {
    background: 'black'
  }
};

/**
 * 响应式
 * @param {object} props
 */
const Response = props => {
  return (
    <Layout>
      <Sider
        breakpoint="lg"
        foldedWidth="0"
        onFolded={(folded, type) => { console.log(folded, type); }}
      >
        <div style={styles.logo} />
        <Nav>
          <NavItem key="1" title="首页" />
          <NavItem key="2" title="用户中心" />
          <NavItem key="3" title="配置" />
        </Nav>
      </Sider>
      <Layout>
        <Header style={styles.header} />
        <Content style={{ margin: '24px 16px 0' }}>
          <div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
            content
          </div>
        </Content>
        <Footer style={{ textAlign: 'center' }}>
          @copyright AMOS
        </Footer>
      </Layout>
    </Layout>
  );
};

ReactDOM.render(<Response />, _react_runner_);
```
---demoend

## props

### Layout

布局容器。

| params | type | default | description |
| ------- | ------ | ------ | ------ |
| style | object | - | 指定样式 |
| className | string | - | 容器 className |

> `Layout.Header` `Layout.Footer` `Layout.Content` props 与 `Layout` 相同

### Layout.Sider

侧边栏。

| params | type | default | description |
| ------- | ------ | ------ | ------ |
| foldable | boolean | false  | 是否可折叠 |
| defaultFolded | boolean | false  | 是否默认折叠 |
| folded | boolean | - | 当前折叠状态 |
| onFolded | (folded, type) => {} | - | 展开-折叠时的回调函数，有点击 trigger 以及响应式反馈两种方式可以触发 |
| trigger | `string、ReactNode` | - | 自定义 trigger，设置为 null 时隐藏 trigger |
| width | `number、string` | 200 | 宽度 |
| foldedWidth | number | 64 | 折叠后的宽度，设置为 0 会出现特殊 trigger |
| breakpoint | string | - | 触发响应式断点，可选值`xs, sm, md, lg, xl` |
| style | object | - | slider 外层div样式 |
| className | string | - | slider 外层div className |

#### breakpoint width

```js
{
  xs: '480px',
  sm: '768px',
  md: '992px',
  lg: '1200px',
  xl: '1600px',
}
```

> 注意：如果你想在 `Sider` 基础上进行包装，需要给自定义组件加上 `__AMOS_LAYOUT_SIDER = true` 设置，例如：

```js
const CustomizedSider = (props) => <Sider {...props} />
CustomizedSider.__AMOS_LAYOUT_SIDER = true;

...

<CustomizedSider>Sider Content</CustomizedSider>
```
