add layout (#6600)

* add layout

* add docs

* add en docs

* fix test
This commit is contained in:
杨奕 2017-08-22 12:46:22 +08:00 committed by GitHub
parent 8e8b172bdc
commit bf6661266a
24 changed files with 945 additions and 4 deletions

View File

@ -8,7 +8,7 @@ var endOfLine = require('os').EOL;
var OUTPUT_PATH = path.join(__dirname, '../../src/index.js');
var IMPORT_TEMPLATE = 'import {{name}} from \'../packages/{{package}}/index.js\';';
var INSTALL_COMPONENT_TEMPLATE = ' {{name}}';
var MAIN_TEMPLATE = `/* Automatic generated by './build/bin/build-entry.js' */
var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-entry.js' */
{{include}}
import locale from 'element-ui/src/locale';

View File

@ -62,5 +62,10 @@
"collapse-item": "./packages/collapse-item/index.js",
"cascader": "./packages/cascader/index.js",
"color-picker": "./packages/color-picker/index.js",
"transfer": "./packages/transfer/index.js"
"transfer": "./packages/transfer/index.js",
"container": "./packages/container/index.js",
"header": "./packages/header/index.js",
"aside": "./packages/aside/index.js",
"main": "./packages/main/index.js",
"footer": "./packages/footer/index.js"
}

View File

@ -0,0 +1,297 @@
<style>
.el-header, .el-footer {
background-color: #1f2d3d;
color: #fff;
line-height: 60px;
}
.el-aside {
color: #fff;
}
#common-layouts + .demo-container {
.el-header, .el-footer {
text-align: center;
}
.el-aside {
background-color: #8492a6;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #d3dce6;
color: #5e6d82;
text-align: center;
line-height: 160px;
}
& > .source > .el-container {
margin-bottom: 40px;
&:nth-child(5) .el-aside,
&:nth-child(6) .el-aside {
line-height: 260px;
}
&:nth-child(7) .el-aside {
line-height: 320px;
}
}
}
</style>
<script>
export default {
data() {
const item = {
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
};
return {
tableData: Array(20).fill(item)
}
}
};
</script>
## Container
Container components for scaffolding basic structure of the page:
`<el-container>`: wrapper container. When nested with a `<el-header>` or `<el-footer>`, all its child elements will be vertically arranged. Otherwise horizontally.
`<el-header>`: container for headers.
`<el-aside>`: container for side sections (usually a side nav).
`<el-main>`: container for main sections.
`<el-footer>`: container for footers.
:::tip
These components use flex for layout, so please make sure your browser supports it. Besides, `<el-container>`'s direct child elements have to be one or more of the latter four components. And father element of the latter four components must be a `<el-container>`.
:::
### Common layouts
::: demo
```html
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
</el-container>
</el-container>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
</el-container>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
</el-container>
<style>
.el-header, .el-footer {
background-color: #1f2d3d;
color: #fff;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #8492a6;
color: #fff;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #d3dce6;
color: #5e6d82;
text-align: center;
line-height: 160px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
</style>
```
:::
### Example
::: demo
```html
<el-container style="height: 500px; border: 1px solid #eee">
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '3']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>Navigator One</template>
<el-menu-item-group>
<template slot="title">Group 1</template>
<el-menu-item index="1-1">Option 1</el-menu-item>
<el-menu-item index="1-2">Option 2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="Group 2">
<el-menu-item index="1-3">Option 3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<template slot="title">Option4</template>
<el-menu-item index="1-4-1">Option 4-1</el-menu-item>
</el-submenu>
</el-submenu>
<el-submenu index="2">
<template slot="title"><i class="el-icon-menu"></i>Navigator Two</template>
<el-menu-item-group>
<template slot="title">Group 1</template>
<el-menu-item index="2-1">Option 1</el-menu-item>
<el-menu-item index="2-2">Option 2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="Group 2">
<el-menu-item index="2-3">Option 3</el-menu-item>
</el-menu-item-group>
<el-submenu index="2-4">
<template slot="title">Option 4</template>
<el-menu-item index="2-4-1">Option 4-1</el-menu-item>
</el-submenu>
</el-submenu>
<el-submenu index="3">
<template slot="title"><i class="el-icon-setting"></i>Navigator Three</template>
<el-menu-item-group>
<template slot="title">Group 1</template>
<el-menu-item index="3-1">Option 1</el-menu-item>
<el-menu-item index="3-2">Option 2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="Group 2">
<el-menu-item index="3-3">Option 3</el-menu-item>
</el-menu-item-group>
<el-submenu index="3-4">
<template slot="title">Option 4</template>
<el-menu-item index="3-4-1">Option 4-1</el-menu-item>
</el-submenu>
</el-submenu>
</el-menu>
</el-aside>
<el-container>
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>View</el-dropdown-item>
<el-dropdown-item>Add</el-dropdown-item>
<el-dropdown-item>Delete</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>Tom</span>
</el-header>
<el-main>
<el-table :data="tableData">
<el-table-column prop="date" label="Date" width="140">
</el-table-column>
<el-table-column prop="name" label="Name" width="120">
</el-table-column>
<el-table-column prop="address" label="Address">
</el-table-column>
</el-table>
</el-main>
</el-container>
</el-container>
<style>
.el-header {
background-color: #1f2d3d;
color: #fff;
line-height: 60px;
}
.el-aside {
color: #fff;
}
</style>
<script>
export default {
data() {
const item = {
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
};
return {
tableData: Array(20).fill(item)
}
}
};
</script>
```
:::
### Container Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- |
| direction | layout direction for child elements | string | horizontal / vertical | vertical when nested with `el-header` or `el-footer`; horizontal otherwise |
### Header Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- |
| height | height of the header | string | — | 60px |
### Aside Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- |
| width | width of the side section | string | — | 300px |
### Footer Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- |
| height | height of the footer | string | — | 60px |

View File

@ -0,0 +1,297 @@
<style>
.el-header, .el-footer {
background-color: #1f2d3d;
color: #fff;
line-height: 60px;
}
.el-aside {
color: #fff;
}
#chang-jian-ye-mian-bu-ju + .demo-container {
.el-header, .el-footer {
text-align: center;
}
.el-aside {
background-color: #8492a6;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #d3dce6;
color: #5e6d82;
text-align: center;
line-height: 160px;
}
& > .source > .el-container {
margin-bottom: 40px;
&:nth-child(5) .el-aside,
&:nth-child(6) .el-aside {
line-height: 260px;
}
&:nth-child(7) .el-aside {
line-height: 320px;
}
}
}
</style>
<script>
export default {
data() {
const item = {
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
};
return {
tableData: Array(20).fill(item)
}
}
};
</script>
## Container 布局容器
用于布局的容器组件,方便快速搭建页面的基本结构:
`<el-container>`:外层容器。当子元素中包含 `<el-header>``<el-footer>` 时,全部子元素会垂直上下排列,否则会水平左右排列。
`<el-header>`:顶栏容器。
`<el-aside>`:侧边栏容器。
`<el-main>`:主要区域容器。
`<el-footer>`:底栏容器。
:::tip
以上组件采用了 flex 布局,使用前请确定目标浏览器是否兼容。此外,`<el-container>` 的子元素只能是后四者,后四者的父元素也只能是 `<el-container>`
:::
### 常见页面布局
::: demo
```html
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
</el-container>
</el-container>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
</el-container>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
</el-container>
<style>
.el-header, .el-footer {
background-color: #1f2d3d;
color: #fff;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #8492a6;
color: #fff;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #d3dce6;
color: #5e6d82;
text-align: center;
line-height: 160px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
</style>
```
:::
### 实例
::: demo
```html
<el-container style="height: 500px; border: 1px solid #eee">
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '3']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>导航一</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="1-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<template slot="title">选项4</template>
<el-menu-item index="1-4-1">选项4-1</el-menu-item>
</el-submenu>
</el-submenu>
<el-submenu index="2">
<template slot="title"><i class="el-icon-menu"></i>导航二</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="2-1">选项1</el-menu-item>
<el-menu-item index="2-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="2-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="2-4">
<template slot="title">选项4</template>
<el-menu-item index="2-4-1">选项4-1</el-menu-item>
</el-submenu>
</el-submenu>
<el-submenu index="3">
<template slot="title"><i class="el-icon-setting"></i>导航三</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="3-1">选项1</el-menu-item>
<el-menu-item index="3-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="3-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="3-4">
<template slot="title">选项4</template>
<el-menu-item index="3-4-1">选项4-1</el-menu-item>
</el-submenu>
</el-submenu>
</el-menu>
</el-aside>
<el-container>
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>查看</el-dropdown-item>
<el-dropdown-item>新增</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>王小虎</span>
</el-header>
<el-main>
<el-table :data="tableData">
<el-table-column prop="date" label="日期" width="140">
</el-table-column>
<el-table-column prop="name" label="姓名" width="120">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</el-main>
</el-container>
</el-container>
<style>
.el-header {
background-color: #1f2d3d;
color: #fff;
line-height: 60px;
}
.el-aside {
color: #fff;
}
</style>
<script>
export default {
data() {
const item = {
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
};
return {
tableData: Array(20).fill(item)
}
}
};
</script>
```
:::
### Container Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------|----------|---------|-------------|--------|
| direction | 子元素的排列方向 | string | horizontal / vertical | 子元素中有 `el-header``el-footer` 时为 vertical否则为 horizontal |
### Header Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------|----------|---------|-------------|--------|
| height | 顶栏高度 | string | — | 60px |
### Aside Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------|----------|---------|-------------|--------|
| width | 侧边栏宽度 | string | — | 300px |
### Footer Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------|----------|---------|-------------|--------|
| height | 底栏高度 | string | — | 60px |

View File

@ -43,6 +43,10 @@
"path": "/layout",
"title": "Layout 布局"
},
{
"path": "/container",
"title": "Container 布局容器"
},
{
"path": "/color",
"title": "Color 色彩"
@ -285,6 +289,10 @@
"path": "/layout",
"title": "Layout"
},
{
"path": "/container",
"title": "Layout Container"
},
{
"path": "/color",
"title": "Color"

8
packages/aside/index.js Normal file
View File

@ -0,0 +1,8 @@
import Aside from './src/main';
/* istanbul ignore next */
Aside.install = function(Vue) {
Vue.component(Aside.name, Aside);
};
export default Aside;

View File

@ -0,0 +1,20 @@
<template>
<aside class="el-aside" :style="{ width }">
<slot></slot>
</aside>
</template>
<script>
export default {
name: 'ElAside',
componentName: 'ElAside',
props: {
width: {
type: String,
default: '300px'
}
}
};
</script>

View File

@ -0,0 +1,8 @@
import Container from './src/main';
/* istanbul ignore next */
Container.install = function(Vue) {
Vue.component(Container.name, Container);
};
export default Container;

View File

@ -0,0 +1,33 @@
<template>
<section class="el-container" :class="{ 'is-vertical': isVertical }">
<slot></slot>
</section>
</template>
<script>
export default {
name: 'ElContainer',
componentName: 'ElContainer',
props: {
direction: String
},
computed: {
isVertical() {
if (this.direction === 'vertical') {
return true;
} else if (this.direction === 'horizontal') {
return false;
}
return this.$slots && this.$slots.default
? this.$slots.default.some(vnode => {
const tag = vnode.componentOptions && vnode.componentOptions.tag;
return tag === 'el-header' || tag === 'el-footer';
})
: false;
}
}
};
</script>

8
packages/footer/index.js Normal file
View File

@ -0,0 +1,8 @@
import Footer from './src/main';
/* istanbul ignore next */
Footer.install = function(Vue) {
Vue.component(Footer.name, Footer);
};
export default Footer;

View File

@ -0,0 +1,20 @@
<template>
<footer class="el-footer" :style="{ height }">
<slot></slot>
</footer>
</template>
<script>
export default {
name: 'ElFooter',
componentName: 'ElFooter',
props: {
height: {
type: String,
default: '60px'
}
}
};
</script>

8
packages/header/index.js Normal file
View File

@ -0,0 +1,8 @@
import Header from './src/main';
/* istanbul ignore next */
Header.install = function(Vue) {
Vue.component(Header.name, Header);
};
export default Header;

View File

@ -0,0 +1,20 @@
<template>
<header class="el-header" :style="{ height }">
<slot></slot>
</header>
</template>
<script>
export default {
name: 'ElHeader',
componentName: 'ElHeader',
props: {
height: {
type: String,
default: '60px'
}
}
};
</script>

8
packages/main/index.js Normal file
View File

@ -0,0 +1,8 @@
import Main from './src/main';
/* istanbul ignore next */
Main.install = function(Vue) {
Vue.component(Main.name, Main);
};
export default Main;

View File

@ -0,0 +1,12 @@
<template>
<main class="el-main">
<slot></slot>
</main>
</template>
<script>
export default {
name: 'ElMain',
componentName: 'ElMain'
};
</script>

View File

@ -0,0 +1,8 @@
@charset "UTF-8";
@component-namespace el {
@b aside {
overflow: auto;
box-sizing: border-box;
}
}

View File

@ -599,4 +599,16 @@
--transfer-item-height: 32px;
--transfer-item-hover-background: var(--color-light-gray);
--transfer-filter-height: 22px;
/* Header
--------------------------*/
--header-padding: 0 20px;
/* Footer
--------------------------*/
--footer-padding: 0 20px;
/* Main
--------------------------*/
--main-padding: 20px;
}

View File

@ -0,0 +1,14 @@
@charset "UTF-8";
@component-namespace el {
@b container {
display: flex;
flex-direction: row;
flex: 1;
box-sizing: border-box;
@when vertical {
flex-direction: column;
}
}
}

View File

@ -0,0 +1,9 @@
@charset "UTF-8";
@import "./common/var.css";
@component-namespace el {
@b footer {
padding: var(--footer-padding);
box-sizing: border-box;
}
}

View File

@ -0,0 +1,9 @@
@charset "UTF-8";
@import "./common/var.css";
@component-namespace el {
@b header {
padding: var(--header-padding);
box-sizing: border-box;
}
}

View File

@ -60,3 +60,8 @@
@import "./cascader.css";
@import "./color-picker.css";
@import "./transfer.css";
@import "./container.css";
@import "./header.css";
@import "./aside.css";
@import "./main.css";
@import "./footer.css";

View File

@ -0,0 +1,11 @@
@charset "UTF-8";
@import "./common/var.css";
@component-namespace el {
@b main {
flex: 1;
overflow: auto;
box-sizing: border-box;
padding: var(--main-padding);
}
}

View File

@ -1,4 +1,4 @@
/* Automatic generated by './build/bin/build-entry.js' */
/* Automatically generated by './build/bin/build-entry.js' */
import Pagination from '../packages/pagination/index.js';
import Dialog from '../packages/dialog/index.js';
@ -64,6 +64,11 @@ import CollapseItem from '../packages/collapse-item/index.js';
import Cascader from '../packages/cascader/index.js';
import ColorPicker from '../packages/color-picker/index.js';
import Transfer from '../packages/transfer/index.js';
import Container from '../packages/container/index.js';
import Header from '../packages/header/index.js';
import Aside from '../packages/aside/index.js';
import Main from '../packages/main/index.js';
import Footer from '../packages/footer/index.js';
import locale from 'element-ui/src/locale';
import CollapseTransition from 'element-ui/src/transitions/collapse-transition';
@ -128,6 +133,11 @@ const components = [
Cascader,
ColorPicker,
Transfer,
Container,
Header,
Aside,
Main,
Footer,
CollapseTransition
];
@ -226,5 +236,10 @@ module.exports = {
CollapseItem,
Cascader,
ColorPicker,
Transfer
Transfer,
Container,
Header,
Aside,
Main,
Footer
};

View File

@ -0,0 +1,106 @@
import { createTest, createVue, destroyVM } from '../util';
import Container from 'packages/container';
import Header from 'packages/header';
import Main from 'packages/main';
import Aside from 'packages/aside';
import Footer from 'packages/footer';
describe('Container', () => {
let vm;
afterEach(() => {
destroyVM(vm);
});
it('create', () => {
vm = createTest(Container, true);
expect(vm.$el).to.exist;
});
it('vertical', () => {
vm = createVue({
template: `
<el-container>
<el-header></el-header>
<el-main></el-main>
</el-container>
`
}, true);
expect(vm.$children[0].$el.classList.contains('is-vertical')).to.true;
});
});
describe('Header', () => {
let vm;
afterEach(() => {
destroyVM(vm);
});
it('create', () => {
vm = createTest(Header, true);
expect(vm.$el).to.exist;
});
it('height', () => {
vm = createVue({
template: `
<el-header height="100px"></el-header>
`
}, true);
expect(vm.$children[0].$el.style.height).to.equal('100px');
});
});
describe('Aside', () => {
let vm;
afterEach(() => {
destroyVM(vm);
});
it('create', () => {
vm = createTest(Aside, true);
expect(vm.$el).to.exist;
});
it('width', () => {
vm = createVue({
template: `
<el-aside width="200px"></el-aside>
`
}, true);
expect(vm.$children[0].$el.style.width).to.equal('200px');
});
});
describe('Main', () => {
let vm;
afterEach(() => {
destroyVM(vm);
});
it('create', () => {
vm = createTest(Main, true);
expect(vm.$el).to.exist;
});
});
describe('Footer', () => {
let vm;
afterEach(() => {
destroyVM(vm);
});
it('create', () => {
vm = createTest(Footer, true);
expect(vm.$el).to.exist;
});
it('height', () => {
vm = createVue({
template: `
<el-footer height="100px"></el-footer>
`
}, true);
expect(vm.$children[0].$el.style.height).to.equal('100px');
});
});