tangjinzhou
7 years ago
14 changed files with 861 additions and 16 deletions
@ -0,0 +1,239 @@ |
|||||||
|
// matchMedia polyfill for |
||||||
|
// https://github.com/WickyNilliams/enquire.js/issues/82 |
||||||
|
if (typeof window !== 'undefined') { |
||||||
|
const matchMediaPolyfill = (mediaQuery) => { |
||||||
|
return { |
||||||
|
media: mediaQuery, |
||||||
|
matches: false, |
||||||
|
addListener () { |
||||||
|
}, |
||||||
|
removeListener () { |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
window.matchMedia = window.matchMedia || matchMediaPolyfill |
||||||
|
} |
||||||
|
|
||||||
|
import classNames from 'classnames' |
||||||
|
import PropTypes from '../_util/vue-types' |
||||||
|
import Icon from '../icon' |
||||||
|
import { initDefaultProps, getOptionProps, hasProp, getComponentFromProp } from '../_util/props-util' |
||||||
|
import BaseMixin from '../_util/BaseMixin' |
||||||
|
|
||||||
|
const dimensionMap = { |
||||||
|
xs: '480px', |
||||||
|
sm: '576px', |
||||||
|
md: '768px', |
||||||
|
lg: '992px', |
||||||
|
xl: '1200px', |
||||||
|
xxl: '1600px', |
||||||
|
} |
||||||
|
|
||||||
|
// export type CollapseType = 'clickTrigger' | 'responsive'; |
||||||
|
|
||||||
|
export const SiderProps = { |
||||||
|
prefixCls: PropTypes.string, |
||||||
|
collapsible: PropTypes.bool, |
||||||
|
collapsed: PropTypes.bool, |
||||||
|
defaultCollapsed: PropTypes.bool, |
||||||
|
reverseArrow: PropTypes.bool, |
||||||
|
// onCollapse?: (collapsed: boolean, type: CollapseType) => void; |
||||||
|
trigger: PropTypes.any, |
||||||
|
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), |
||||||
|
collapsedWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), |
||||||
|
breakpoint: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl', 'xxl']), |
||||||
|
} |
||||||
|
|
||||||
|
// export interface SiderState { |
||||||
|
// collapsed?: boolean; |
||||||
|
// below: boolean; |
||||||
|
// belowShow?: boolean; |
||||||
|
// } |
||||||
|
|
||||||
|
// export interface SiderContext { |
||||||
|
// siderCollapsed: boolean; |
||||||
|
// } |
||||||
|
|
||||||
|
const generateId = (() => { |
||||||
|
let i = 0 |
||||||
|
return (prefix = '') => { |
||||||
|
i += 1 |
||||||
|
return `${prefix}${i}` |
||||||
|
} |
||||||
|
})() |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'ALayoutSider', |
||||||
|
__ANT_LAYOUT_SIDER: true, |
||||||
|
mixins: [BaseMixin], |
||||||
|
props: initDefaultProps(SiderProps, { |
||||||
|
prefixCls: 'ant-layout-sider', |
||||||
|
collapsible: false, |
||||||
|
defaultCollapsed: false, |
||||||
|
reverseArrow: false, |
||||||
|
width: 200, |
||||||
|
collapsedWidth: 80, |
||||||
|
}), |
||||||
|
|
||||||
|
// static childContextTypes = { |
||||||
|
// siderCollapsed: PropTypes.bool, |
||||||
|
// collapsedWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), |
||||||
|
// }; |
||||||
|
|
||||||
|
// static contextTypes = { |
||||||
|
// siderHook: PropTypes.object, |
||||||
|
// }; |
||||||
|
|
||||||
|
// private mql: MediaQueryList; |
||||||
|
// private uniqueId: string; |
||||||
|
|
||||||
|
data () { |
||||||
|
this.uniqueId = generateId('ant-sider-') |
||||||
|
let matchMedia |
||||||
|
if (typeof window !== 'undefined') { |
||||||
|
matchMedia = window.matchMedia |
||||||
|
} |
||||||
|
const props = getOptionProps(this) |
||||||
|
if (matchMedia && props.breakpoint && props.breakpoint in dimensionMap) { |
||||||
|
this.mql = matchMedia(`(max-width: ${dimensionMap[props.breakpoint]})`) |
||||||
|
} |
||||||
|
let sCollapsed |
||||||
|
if ('collapsed' in props) { |
||||||
|
sCollapsed = props.collapsed |
||||||
|
} else { |
||||||
|
sCollapsed = props.defaultCollapsed |
||||||
|
} |
||||||
|
return { |
||||||
|
sCollapsed, |
||||||
|
below: false, |
||||||
|
belowShow: false, |
||||||
|
} |
||||||
|
}, |
||||||
|
provide () { |
||||||
|
return { |
||||||
|
layoutSiderContext: this, // menu组件中使用 |
||||||
|
} |
||||||
|
}, |
||||||
|
inject: { |
||||||
|
siderHook: { default: {}}, |
||||||
|
}, |
||||||
|
// getChildContext() { |
||||||
|
// return { |
||||||
|
// siderCollapsed: this.state.collapsed, |
||||||
|
// collapsedWidth: this.props.collapsedWidth, |
||||||
|
// }; |
||||||
|
// } |
||||||
|
watch: { |
||||||
|
collapsed (val) { |
||||||
|
this.setState({ |
||||||
|
sCollapsed: val, |
||||||
|
}) |
||||||
|
}, |
||||||
|
}, |
||||||
|
|
||||||
|
mounted () { |
||||||
|
this.$nextTick(() => { |
||||||
|
if (this.mql) { |
||||||
|
this.mql.addListener(this.responsiveHandler) |
||||||
|
this.responsiveHandler(this.mql) |
||||||
|
} |
||||||
|
|
||||||
|
if (this.siderHook.addSider) { |
||||||
|
this.siderHook.addSider(this.uniqueId) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
beforeDestroy () { |
||||||
|
if (this.mql) { |
||||||
|
this.mql.removeListener(this.responsiveHandler) |
||||||
|
} |
||||||
|
|
||||||
|
if (this.siderHook.removeSider) { |
||||||
|
this.siderHook.removeSider(this.uniqueId) |
||||||
|
} |
||||||
|
}, |
||||||
|
model: { |
||||||
|
prop: 'collapsed', |
||||||
|
event: 'collapse', |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
responsiveHandler (mql) { |
||||||
|
this.setState({ below: mql.matches }) |
||||||
|
if (this.sCollapsed !== mql.matches) { |
||||||
|
this.setCollapsed(mql.matches, 'responsive') |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
setCollapsed (collapsed, type) { |
||||||
|
if (!hasProp(this, 'collapsed')) { |
||||||
|
this.setState({ |
||||||
|
sCollapsed: collapsed, |
||||||
|
}) |
||||||
|
} |
||||||
|
this.$emit('collapse', collapsed, type) |
||||||
|
}, |
||||||
|
|
||||||
|
toggle () { |
||||||
|
const collapsed = !this.sCollapsed |
||||||
|
this.setCollapsed(collapsed, 'clickTrigger') |
||||||
|
}, |
||||||
|
|
||||||
|
belowShowChange () { |
||||||
|
this.setState({ belowShow: !this.belowShow }) |
||||||
|
}, |
||||||
|
}, |
||||||
|
|
||||||
|
render () { |
||||||
|
const { prefixCls, |
||||||
|
collapsible, reverseArrow, width, collapsedWidth, |
||||||
|
} = getOptionProps(this) |
||||||
|
const trigger = getComponentFromProp(this, 'trigger') |
||||||
|
let siderWidth = this.sCollapsed ? collapsedWidth : width |
||||||
|
siderWidth = typeof siderWidth === 'string' ? siderWidth.replace('px', '') : siderWidth |
||||||
|
// special trigger when collapsedWidth == 0 |
||||||
|
const zeroWidthTrigger = collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px' ? ( |
||||||
|
<span onClick={this.toggle} class={`${prefixCls}-zero-width-trigger`}> |
||||||
|
<Icon type='bars' /> |
||||||
|
</span> |
||||||
|
) : null |
||||||
|
const iconObj = { |
||||||
|
'expanded': reverseArrow ? <Icon type='right' /> : <Icon type='left' />, |
||||||
|
'collapsed': reverseArrow ? <Icon type='left' /> : <Icon type='right' />, |
||||||
|
} |
||||||
|
const status = this.sCollapsed ? 'collapsed' : 'expanded' |
||||||
|
const defaultTrigger = iconObj[status] |
||||||
|
const triggerDom = ( |
||||||
|
trigger !== null |
||||||
|
? zeroWidthTrigger || ( |
||||||
|
<div className={`${prefixCls}-trigger`} onClick={this.toggle} style={{ width: `${siderWidth}px` }}> |
||||||
|
{trigger || defaultTrigger} |
||||||
|
</div> |
||||||
|
) : null |
||||||
|
) |
||||||
|
const divStyle = { |
||||||
|
// ...style, |
||||||
|
flex: `0 0 ${siderWidth}px`, |
||||||
|
maxWidth: `${siderWidth}px`, // Fix width transition bug in IE11 |
||||||
|
minWidth: `${siderWidth}px`, // https://github.com/ant-design/ant-design/issues/6349 |
||||||
|
width: `${siderWidth}px`, |
||||||
|
} |
||||||
|
const siderCls = classNames(prefixCls, { |
||||||
|
[`${prefixCls}-collapsed`]: !!this.sCollapsed, |
||||||
|
[`${prefixCls}-has-trigger`]: collapsible && trigger !== null && !zeroWidthTrigger, |
||||||
|
[`${prefixCls}-below`]: !!this.below, |
||||||
|
[`${prefixCls}-zero-width`]: siderWidth === 0 || siderWidth === '0' || siderWidth === '0px', |
||||||
|
}) |
||||||
|
const divProps = { |
||||||
|
on: this.$listeners, |
||||||
|
class: siderCls, |
||||||
|
style: divStyle, |
||||||
|
} |
||||||
|
return ( |
||||||
|
<div {...divProps}> |
||||||
|
<div class={`${prefixCls}-children`}>{this.$slots.default}</div> |
||||||
|
{collapsible || (this.below && zeroWidthTrigger) ? triggerDom : null} |
||||||
|
</div> |
||||||
|
) |
||||||
|
}, |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
<cn> |
||||||
|
#### 基本结构 |
||||||
|
典型的页面布局。 |
||||||
|
</cn> |
||||||
|
|
||||||
|
<us> |
||||||
|
#### Basic Structure |
||||||
|
Classic page layouts. |
||||||
|
</us> |
||||||
|
|
||||||
|
```html |
||||||
|
<template> |
||||||
|
<div id="components-layout-demo-basic"> |
||||||
|
<a-layout> |
||||||
|
<a-layout-header>Header</a-layout-header> |
||||||
|
<a-layout-content>Content</a-layout-content> |
||||||
|
<a-layout-footer>Footer</a-layout-footer> |
||||||
|
</a-layout> |
||||||
|
|
||||||
|
<a-layout> |
||||||
|
<a-layout-header>Header</a-layout-header> |
||||||
|
<a-layout> |
||||||
|
<a-layout-sider>Sider</a-layout-sider> |
||||||
|
<a-layout-content>Content</a-layout-content> |
||||||
|
</a-layout> |
||||||
|
<a-layout-footer>Footer</a-layout-footer> |
||||||
|
</a-layout> |
||||||
|
|
||||||
|
<a-layout> |
||||||
|
<a-layout-header>Header</a-layout-header> |
||||||
|
<a-layout> |
||||||
|
<a-layout-content>Content</a-layout-content> |
||||||
|
<a-layout-sider>Sider</a-layout-sider> |
||||||
|
</a-layout> |
||||||
|
<a-layout-footer>Footer</a-layout-footer> |
||||||
|
</a-layout> |
||||||
|
|
||||||
|
<a-layout> |
||||||
|
<a-layout-sider>Sider</a-layout-sider> |
||||||
|
<a-layout> |
||||||
|
<a-layout-header>Header</a-layout-header> |
||||||
|
<a-layout-content>Content</a-layout-content> |
||||||
|
<a-layout-footer>Footer</a-layout-footer> |
||||||
|
</a-layout> |
||||||
|
</a-layout> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style> |
||||||
|
#components-layout-demo-basic { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
#components-layout-demo-basic .ant-layout-header, |
||||||
|
#components-layout-demo-basic .ant-layout-footer { |
||||||
|
background: #7dbcea; |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
#components-layout-demo-basic .ant-layout-footer { |
||||||
|
line-height: 1.5; |
||||||
|
} |
||||||
|
#components-layout-demo-basic .ant-layout-sider { |
||||||
|
background: #3ba0e9; |
||||||
|
color: #fff; |
||||||
|
line-height: 120px; |
||||||
|
} |
||||||
|
#components-layout-demo-basic .ant-layout-content { |
||||||
|
background: rgba(16, 142, 233, 1); |
||||||
|
color: #fff; |
||||||
|
min-height: 120px; |
||||||
|
line-height: 120px; |
||||||
|
} |
||||||
|
#components-layout-demo-basic > .ant-layout { |
||||||
|
margin-bottom: 48px; |
||||||
|
} |
||||||
|
#components-layout-demo-basic > .ant-layout:last-child { |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
</style> |
||||||
|
``` |
@ -0,0 +1,77 @@ |
|||||||
|
<cn> |
||||||
|
#### 自定义触发器 |
||||||
|
要使用自定义触发器,可以设置 `:trigger="null"` 来隐藏默认设定。 |
||||||
|
</cn> |
||||||
|
|
||||||
|
<us> |
||||||
|
#### Custom trigger |
||||||
|
If you want to use a customized trigger, you can hide the default one by setting `:trigger="null"`. |
||||||
|
</us> |
||||||
|
|
||||||
|
```html |
||||||
|
<template> |
||||||
|
<a-layout id="components-layout-demo-custom-trigger"> |
||||||
|
<a-layout-sider |
||||||
|
:trigger="null" |
||||||
|
collapsible |
||||||
|
v-model="collapsed" |
||||||
|
> |
||||||
|
<div class="logo" /> |
||||||
|
<a-menu theme="dark" mode="inline" defaultSelectedKeys={['1']}> |
||||||
|
<a-menu-item key="1"> |
||||||
|
<a-icon type="user" /> |
||||||
|
<span>nav 1</span> |
||||||
|
</a-menu-item> |
||||||
|
<a-menu-item key="2"> |
||||||
|
<a-icon type="video-camera" /> |
||||||
|
<span>nav 2</span> |
||||||
|
</a-menu-item> |
||||||
|
<a-menu-item key="3"> |
||||||
|
<a-icon type="upload" /> |
||||||
|
<span>nav 3</span> |
||||||
|
</a-menu-item> |
||||||
|
</a-menu> |
||||||
|
</a-layout-sider> |
||||||
|
<a-layout> |
||||||
|
<a-header style="background: #fff; padding: 0"> |
||||||
|
<a-icon |
||||||
|
class="trigger" |
||||||
|
:type="collapsed ? 'menu-unfold' : 'menu-fold'" |
||||||
|
@click="()=> collapsed = !collapsed" |
||||||
|
/> |
||||||
|
</a-header> |
||||||
|
<a-layout-content :style="{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }"> |
||||||
|
Content |
||||||
|
</a-layout-content> |
||||||
|
</a-layout> |
||||||
|
</a-layout> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
data(){ |
||||||
|
return { |
||||||
|
collapsed: false, |
||||||
|
} |
||||||
|
}, |
||||||
|
} |
||||||
|
</script> |
||||||
|
<style> |
||||||
|
#components-layout-demo-custom-trigger .trigger { |
||||||
|
font-size: 18px; |
||||||
|
line-height: 64px; |
||||||
|
padding: 0 24px; |
||||||
|
cursor: pointer; |
||||||
|
transition: color .3s; |
||||||
|
} |
||||||
|
|
||||||
|
#components-layout-demo-custom-trigger .trigger:hover { |
||||||
|
color: #1890ff; |
||||||
|
} |
||||||
|
|
||||||
|
#components-layout-demo-custom-trigger .logo { |
||||||
|
height: 32px; |
||||||
|
background: rgba(255,255,255,.2); |
||||||
|
margin: 16px; |
||||||
|
} |
||||||
|
</style> |
||||||
|
``` |
@ -0,0 +1,113 @@ |
|||||||
|
--- |
||||||
|
category: Components |
||||||
|
type: Layout |
||||||
|
cols: 1 |
||||||
|
title: Layout |
||||||
|
--- |
||||||
|
|
||||||
|
Handling the overall layout of a page. |
||||||
|
|
||||||
|
## Specification |
||||||
|
|
||||||
|
### Size |
||||||
|
|
||||||
|
The first level navigation is inclined left near a logo, and the secondary menu is inclined right. |
||||||
|
|
||||||
|
- Top Navigation (almost systems): the height of the first level navigation `64px`, the second level navigation `48px`. |
||||||
|
- Top Navigation(contents page): the height of the first level navigation `80px`, the second level navigation `56px`. |
||||||
|
- Calculation formula of a top navigation: `48+8n`. |
||||||
|
- Calculation formula of an aside navigation: `200+8n`. |
||||||
|
|
||||||
|
### Interaction rules |
||||||
|
|
||||||
|
- The first level navigation and the last level navigation should be distincted by visualization; |
||||||
|
- The current item should have the highest priority of visualization; |
||||||
|
- When the current navigation item is collapsed, the stlye of the current navigation item will be applied to its parent level; |
||||||
|
- The left side navigation bar has support for both the accordion and expanding styles, you can choose the one that fits your case best. |
||||||
|
|
||||||
|
## Visualization rules |
||||||
|
|
||||||
|
Style of a navigation should conform to its level. |
||||||
|
|
||||||
|
- **Emphasis by colorblock** |
||||||
|
|
||||||
|
When background color is a deep color, you can use this pattern for the parent level navigation item of current page. |
||||||
|
|
||||||
|
- **The highlight match stick** |
||||||
|
|
||||||
|
When background color is a light color, you can use this pattern for the current page navigation item, we recommed using it for the last item of the navigation path. |
||||||
|
|
||||||
|
- **Hightlighted font** |
||||||
|
|
||||||
|
From the visualization aspect, hightlighted font is stronger than colorblock, this pattern is often used for the parent level of the current item. |
||||||
|
|
||||||
|
- **Enlarge the size of the font** |
||||||
|
|
||||||
|
`12px`、`14px` is a standard font size of navigations,`14px` is used for the first and the second level of the navigation. You can choose a appropriate font size in terms of the level of your navigation. |
||||||
|
|
||||||
|
## Component Overview |
||||||
|
|
||||||
|
- `Layout`: The layout wrapper, in which `Header` `Sider` `Content` `Footer` or `Layout` itself can be nested, and can be placed in any parent container. |
||||||
|
- `Header`: The top layout with default style, in which any element can be nested, and must be placed in `Layout`. |
||||||
|
- `Sider`: The sidebar with default style and basic functions, in which any element can be nested, and must be placed in `Layout`. |
||||||
|
- `Content`: The content layout with default style, in which any element can be nested, and must be placed in `Layout`. |
||||||
|
- `Footer`: The bottom layout with default style, in which any element can be nested, and must be placed in `Layout`. |
||||||
|
|
||||||
|
> Based on `flex layout`, please pay attention to the [compatibility](http://caniuse.com/#search=flex). |
||||||
|
|
||||||
|
## API |
||||||
|
|
||||||
|
```jsx |
||||||
|
<Layout> |
||||||
|
<Header>header</Header> |
||||||
|
<Layout> |
||||||
|
<Sider>left sidebar</Sider> |
||||||
|
<Content>main content</Content> |
||||||
|
<Sider>right sidebar</Sider> |
||||||
|
</Layout> |
||||||
|
<Footer>footer</Footer> |
||||||
|
</Layout> |
||||||
|
``` |
||||||
|
|
||||||
|
### Layout |
||||||
|
|
||||||
|
The wrapper. |
||||||
|
|
||||||
|
| Property | Description | Type | Default | |
||||||
|
| -------- | ----------- | ---- | ------- | |
||||||
|
| className | container className | string | - | |
||||||
|
| style | to customize the styles | object | - | |
||||||
|
| hasSider | whether contain Sider in children, don't have to assign it normally. Useful in ssr avoid style flickering | boolean | - | |
||||||
|
|
||||||
|
> APIs of `Layout.Header` `Layout.Footer` `Layout.Content` are the same as that of `Layout`. |
||||||
|
|
||||||
|
### Layout.Sider |
||||||
|
|
||||||
|
The sidebar. |
||||||
|
|
||||||
|
| Property | Description | Type | Default | |
||||||
|
| -------- | ----------- | ---- | ------- | |
||||||
|
| breakpoint | [breakpoints](/components/grid#api) of the responsive layout | Enum { 'xs', 'sm', 'md', 'lg', 'xl', 'xxl' } | - | |
||||||
|
| className | container className | string | - | |
||||||
|
| collapsed | to set the current status | boolean | - | |
||||||
|
| collapsedWidth | width of the collapsed sidebar, by setting to `0` a special trigger will appear | number | 64 | |
||||||
|
| collapsible | whether can be collapsed | boolean | false | |
||||||
|
| defaultCollapsed | to set the initial status | boolean | false | |
||||||
|
| reverseArrow | reverse direction of arrow, for a sider that expands from the right | boolean | false | |
||||||
|
| style | to customize the styles | object | - | |
||||||
|
| trigger | specify the customized trigger, set to null to hide the trigger | string\|ReactNode | - | |
||||||
|
| width | width of the sidebar | number\|string | 200 | |
||||||
|
| onCollapse | the callback function, executed by clicking the trigger or activating the responsive layout | (collapsed, type) => {} | - | |
||||||
|
|
||||||
|
#### breakpoint width |
||||||
|
|
||||||
|
```js |
||||||
|
{ |
||||||
|
xs: '480px', |
||||||
|
sm: '576px', |
||||||
|
md: '768px', |
||||||
|
lg: '992px', |
||||||
|
xl: '1200px', |
||||||
|
xxl: '1600px', |
||||||
|
} |
||||||
|
``` |
@ -0,0 +1,5 @@ |
|||||||
|
import Layout from './layout' |
||||||
|
import Sider from './Sider' |
||||||
|
|
||||||
|
Layout.Sider = Sider |
||||||
|
export default Layout |
@ -0,0 +1,114 @@ |
|||||||
|
--- |
||||||
|
category: Components |
||||||
|
subtitle: 布局 |
||||||
|
type: Layout |
||||||
|
cols: 1 |
||||||
|
title: Layout |
||||||
|
--- |
||||||
|
|
||||||
|
协助进行页面级整体布局。 |
||||||
|
|
||||||
|
## 设计规则 |
||||||
|
|
||||||
|
### 尺寸 |
||||||
|
|
||||||
|
一级导航项偏左靠近 logo 放置,辅助菜单偏右放置。 |
||||||
|
|
||||||
|
- 顶部导航(大部分系统):一级导航高度 `64px`,二级导航 `48px`。 |
||||||
|
- 顶部导航(展示类页面):一级导航高度 `80px`,二级导航 `56px`。 |
||||||
|
- 顶部导航高度的范围计算公式为:`48+8n`。 |
||||||
|
- 侧边导航宽度的范围计算公式:`200+8n`。 |
||||||
|
|
||||||
|
### 交互 |
||||||
|
|
||||||
|
- 一级导航和末级的导航需要在可视化的层面被强调出来; |
||||||
|
- 当前项应该在呈现上优先级最高; |
||||||
|
- 当导航收起的时候,当前项的样式自动赋予给它的上一个层级; |
||||||
|
- 左侧导航栏的收放交互同时支持手风琴和全展开的样式,根据业务的要求进行适当的选择。 |
||||||
|
|
||||||
|
### 视觉 |
||||||
|
|
||||||
|
导航样式上需要根据信息层级合理的选择样式: |
||||||
|
|
||||||
|
- **大色块强调** |
||||||
|
|
||||||
|
建议用于底色为深色系时,当前页面父级的导航项。 |
||||||
|
|
||||||
|
- **高亮火柴棍** |
||||||
|
|
||||||
|
当导航栏底色为浅色系时使用,可用于当前页面对应导航项,建议尽量在导航路径的最终项使用。 |
||||||
|
|
||||||
|
- **字体高亮变色** |
||||||
|
|
||||||
|
从可视化层面,字体高亮的视觉强化力度低于大色块,通常在当前项的上一级使用。 |
||||||
|
|
||||||
|
- **字体放大** |
||||||
|
|
||||||
|
`12px`、`14px` 是导航的标准字号,14 号字体用在一、二级导航中。字号可以考虑导航项的等级做相应选择。 |
||||||
|
|
||||||
|
## 组件概述 |
||||||
|
|
||||||
|
- `Layout`:布局容器,其下可嵌套 `Header` `Sider` `Content` `Footer` 或 `Layout` 本身,可以放在任何父容器中。 |
||||||
|
- `Header`:顶部布局,自带默认样式,其下可嵌套任何元素,只能放在 `Layout` 中。 |
||||||
|
- `Sider`:侧边栏,自带默认样式及基本功能,其下可嵌套任何元素,只能放在 `Layout` 中。 |
||||||
|
- `Content`:内容部分,自带默认样式,其下可嵌套任何元素,只能放在 `Layout` 中。 |
||||||
|
- `Footer`:底部布局,自带默认样式,其下可嵌套任何元素,只能放在 `Layout` 中。 |
||||||
|
|
||||||
|
> 注意:采用 flex 布局实现,请注意[浏览器兼容性](http://caniuse.com/#search=flex)问题。 |
||||||
|
|
||||||
|
## API |
||||||
|
|
||||||
|
```jsx |
||||||
|
<Layout> |
||||||
|
<Header>header</Header> |
||||||
|
<Layout> |
||||||
|
<Sider>left sidebar</Sider> |
||||||
|
<Content>main content</Content> |
||||||
|
<Sider>right sidebar</Sider> |
||||||
|
</Layout> |
||||||
|
<Footer>footer</Footer> |
||||||
|
</Layout> |
||||||
|
``` |
||||||
|
|
||||||
|
### Layout |
||||||
|
|
||||||
|
布局容器。 |
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | |
||||||
|
| --- | --- | --- | --- | |
||||||
|
| class | 容器 class | string | - | |
||||||
|
| style | 指定样式 | object | - | |
||||||
|
| hasSider | 表示子元素里有 Sider,一般不用指定。可用于服务端渲染时避免样式闪动 | boolean | - | |
||||||
|
|
||||||
|
> `Layout.Header` `Layout.Footer` `Layout.Content` API 与 `Layout` 相同 |
||||||
|
|
||||||
|
### Layout.Sider |
||||||
|
|
||||||
|
侧边栏。 |
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | |
||||||
|
| --- | --- | --- | --- | |
||||||
|
| breakpoint | 触发响应式布局的[断点](/components/grid#api) | Enum { 'xs', 'sm', 'md', 'lg', 'xl', 'xxl' } | - | |
||||||
|
| class | 容器 class | string | - | |
||||||
|
| collapsed | 当前收起状态 | boolean | - | |
||||||
|
| collapsedWidth | 收缩宽度,设置为 0 会出现特殊 trigger | number | 64 | |
||||||
|
| collapsible | 是否可收起 | boolean | false | |
||||||
|
| defaultCollapsed | 是否默认收起 | boolean | false | |
||||||
|
| reverseArrow | 翻转折叠提示箭头的方向,当 Sider 在右边时可以使用 | boolean | false | |
||||||
|
| style | 指定样式 | object | - | |
||||||
|
| trigger | 自定义 trigger,设置为 null 时隐藏 trigger | string\|slot | - | |
||||||
|
| width | 宽度 | number\|string | 200 | |
||||||
|
| onCollapse | 展开-收起时的回调函数,有点击 trigger 以及响应式反馈两种方式可以触发 | (collapsed, type) => {} | - | |
||||||
|
|
||||||
|
#### breakpoint width |
||||||
|
|
||||||
|
```js |
||||||
|
{ |
||||||
|
xs: '480px', |
||||||
|
sm: '576px', |
||||||
|
md: '768px', |
||||||
|
lg: '992px', |
||||||
|
xl: '1200px', |
||||||
|
xxl: '1600px', |
||||||
|
} |
||||||
|
``` |
@ -0,0 +1,98 @@ |
|||||||
|
import PropTypes from '../_util/vue-types' |
||||||
|
import classNames from 'classnames' |
||||||
|
import { getOptionProps } from '../_util/props-util' |
||||||
|
|
||||||
|
export const BasicProps = { |
||||||
|
prefixCls: PropTypes.string, |
||||||
|
hasSider: PropTypes.boolean, |
||||||
|
} |
||||||
|
|
||||||
|
function generator (props, name) { |
||||||
|
return (BasicComponent) => { |
||||||
|
return { |
||||||
|
name, |
||||||
|
props: BasicComponent.props, |
||||||
|
render () { |
||||||
|
const { prefixCls } = props |
||||||
|
const basicComponentProps = { |
||||||
|
props: { |
||||||
|
prefixCls, |
||||||
|
...getOptionProps(this), |
||||||
|
}, |
||||||
|
on: this.$listeners, |
||||||
|
} |
||||||
|
return <BasicComponent {...basicComponentProps}>{this.$slots.default}</BasicComponent> |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const Basic = { |
||||||
|
props: BasicProps, |
||||||
|
render () { |
||||||
|
const { prefixCls, $slots, $listeners } = this |
||||||
|
const divProps = { |
||||||
|
class: prefixCls, |
||||||
|
on: $listeners, |
||||||
|
} |
||||||
|
return ( |
||||||
|
<div {...divProps}>{$slots.default}</div> |
||||||
|
) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const BasicLayout = { |
||||||
|
props: BasicProps, |
||||||
|
data () { |
||||||
|
return { |
||||||
|
siders: [], |
||||||
|
} |
||||||
|
}, |
||||||
|
provide () { |
||||||
|
return { |
||||||
|
siderHook: { |
||||||
|
addSider: (id) => { |
||||||
|
this.siders = [...this.siders, id] |
||||||
|
}, |
||||||
|
removeSider: (id) => { |
||||||
|
this.siders = this.siders.filter(currentId => currentId !== id) |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
}, |
||||||
|
render () { |
||||||
|
const { prefixCls, $slots, hasSider, $listeners } = this |
||||||
|
const divCls = classNames(prefixCls, { |
||||||
|
[`${prefixCls}-has-sider`]: hasSider || this.siders.length > 0, |
||||||
|
}) |
||||||
|
const divProps = { |
||||||
|
class: divCls, |
||||||
|
on: $listeners, |
||||||
|
} |
||||||
|
return ( |
||||||
|
<div {...divProps}>{$slots.default}</div> |
||||||
|
) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const Layout = generator({ |
||||||
|
prefixCls: 'ant-layout', |
||||||
|
}, 'ALayout')(BasicLayout) |
||||||
|
|
||||||
|
const Header = generator({ |
||||||
|
prefixCls: 'ant-layout-header', |
||||||
|
}, 'ALayoutHeader')(Basic) |
||||||
|
|
||||||
|
const Footer = generator({ |
||||||
|
prefixCls: 'ant-layout-footer', |
||||||
|
}, 'ALayoutFooter')(Basic) |
||||||
|
|
||||||
|
const Content = generator({ |
||||||
|
prefixCls: 'ant-layout-content', |
||||||
|
}, 'ALayoutContent')(Basic) |
||||||
|
|
||||||
|
Layout.Header = Header |
||||||
|
Layout.Footer = Footer |
||||||
|
Layout.Content = Content |
||||||
|
|
||||||
|
export default Layout |
@ -0,0 +1,2 @@ |
|||||||
|
import '../../style/index.less' |
||||||
|
import './index.less' |
@ -0,0 +1,112 @@ |
|||||||
|
@import "../../style/themes/default"; |
||||||
|
@import "../../style/mixins/index"; |
||||||
|
|
||||||
|
@layout-prefix-cls: ~"@{ant-prefix}-layout"; |
||||||
|
|
||||||
|
.@{layout-prefix-cls} { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
flex: auto; |
||||||
|
background: @layout-body-background; |
||||||
|
|
||||||
|
&, |
||||||
|
* { |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
|
||||||
|
&&-has-sider { |
||||||
|
flex-direction: row; |
||||||
|
> .@{layout-prefix-cls}, |
||||||
|
> .@{layout-prefix-cls}-content { |
||||||
|
overflow-x: hidden; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&-header, |
||||||
|
&-footer { |
||||||
|
flex: 0 0 auto; |
||||||
|
} |
||||||
|
|
||||||
|
&-header { |
||||||
|
background: @layout-header-background; |
||||||
|
padding: @layout-header-padding; |
||||||
|
height: @layout-header-height; |
||||||
|
line-height: @layout-header-height; |
||||||
|
} |
||||||
|
|
||||||
|
&-footer { |
||||||
|
background: @layout-footer-background; |
||||||
|
padding: @layout-footer-padding; |
||||||
|
color: @text-color; |
||||||
|
font-size: @font-size-base; |
||||||
|
} |
||||||
|
|
||||||
|
&-content { |
||||||
|
flex: auto; |
||||||
|
} |
||||||
|
|
||||||
|
&-sider { |
||||||
|
transition: all .2s; |
||||||
|
position: relative; |
||||||
|
background: @layout-sider-background; |
||||||
|
|
||||||
|
/* fix firefox can't set width smaller than content on flex item */ |
||||||
|
min-width: 0; |
||||||
|
|
||||||
|
&-children { |
||||||
|
height: 100%; |
||||||
|
// Hack for fixing margin collaspe bug |
||||||
|
// https://github.com/ant-design/ant-design/issues/7967 |
||||||
|
// solution from https://stackoverflow.com/a/33132624/3040605 |
||||||
|
padding-top: 0.1px; |
||||||
|
margin-top: -0.1px; |
||||||
|
} |
||||||
|
|
||||||
|
&-has-trigger { |
||||||
|
padding-bottom: @layout-trigger-height; |
||||||
|
} |
||||||
|
|
||||||
|
&-right { |
||||||
|
order: 1; |
||||||
|
} |
||||||
|
|
||||||
|
&-trigger { |
||||||
|
position: fixed; |
||||||
|
text-align: center; |
||||||
|
bottom: 0; |
||||||
|
cursor: pointer; |
||||||
|
height: @layout-trigger-height; |
||||||
|
line-height: @layout-trigger-height; |
||||||
|
color: @layout-trigger-color; |
||||||
|
background: @layout-trigger-background; |
||||||
|
z-index: 1; |
||||||
|
transition: all .2s; |
||||||
|
} |
||||||
|
|
||||||
|
&-zero-width { |
||||||
|
& > * { |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
&-trigger { |
||||||
|
position: absolute; |
||||||
|
top: @layout-header-height; |
||||||
|
right: -@layout-zero-trigger-width; |
||||||
|
text-align: center; |
||||||
|
width: @layout-zero-trigger-width; |
||||||
|
height: @layout-zero-trigger-height; |
||||||
|
line-height: @layout-zero-trigger-height; |
||||||
|
background: @layout-sider-background; |
||||||
|
color: @layout-trigger-color; |
||||||
|
font-size: @layout-zero-trigger-width / 2; |
||||||
|
border-radius: 0 @border-radius-base @border-radius-base 0; |
||||||
|
cursor: pointer; |
||||||
|
transition: background .3s ease; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
background: tint(@layout-sider-background, 10%); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue