Merge branch 'dev' into 1.1

pull/2036/head
杨奕 2016-12-28 15:23:51 +08:00 committed by GitHub
commit d2f02b828f
65 changed files with 1791 additions and 770 deletions

View File

@ -1,5 +1,22 @@
## Changelog ## Changelog
### 1.0.9
*2016-12-27*
- Fixed DatePicker incorrectly triggering input event, #1834
- Fixed Tree reporting `event is undefined` error in Firefox, #1945
- Added `change` event for DatePicker, whose parameter is the formatted value, #1841
- Added `header-align` attribute for Table, #1424
- Fixed single select Table's highlight style not removing when data is removed, #1890
- Fixed filterable Select lagging issue with more options, #1933
- Fixed multiple disabled Select not disabling removing selected options issue, #2001
- Fixed Col style not working in `xs`, #2011
- Added `value` attribute for Tab, #2008
- Fixed InputNumber `change` event incorrectly firing multiple times in some conditions, #1999
- Added `clearable` attribute for DatePicker, #1994
- Fixed Form always passing validation in async mode, #1936
### 1.0.8 ### 1.0.8
*2016-12-20* *2016-12-20*

View File

@ -1,5 +1,21 @@
## 更新日志 ## 更新日志
### 1.0.9
*2016-12-27*
- 修复 DatePicker 不能正确触发 input 事件的问题,现在只有当日期改变时才触发,#1834
- 修复 Tree 在 Firefox 下会提示 event is undefined 的问题,#1945
- 新增 DatePicker 的 `change` 事件,返回和输入框一致的格式化后的值,#1841
- 新增 Table 的 `header-align` 属性,#1424
- 修复单选的 Table 在数据移除时,高亮状态仍然存在的问题,#1890
- 修复可搜索的 Select 在选项较多时的卡顿问题,#1933
- 修复多选的 Select 在禁用状态下仍然能够手动删除选中项的问题,#2001
- 修复 Col `xs` 分辨率下样式无效的问题,#2011
- 新增 Tab 组件的 `value` 属性并支持 `v-model` 用法,#2008
- 修复 Input Number 在某些条件下 change 事件被触发多次的问题,#1999
- 新增 DatePicker 的 `clearable` 属性,#1994
- 修复 Form 异步验证时某些条件下总是验证通过的问题,#1936
### 1.0.8 ### 1.0.8
*2016-12-20* *2016-12-20*

View File

@ -1,6 +1,7 @@
var cooking = require('cooking'); var cooking = require('cooking');
var config = require('./config'); var config = require('./config');
var md = require('markdown-it')(); var md = require('markdown-it')();
var CopyWebpackPlugin = require('copy-webpack-plugin');
var striptags = require('./strip-tags'); var striptags = require('./strip-tags');
var slugify = require('transliteration').slugify; var slugify = require('transliteration').slugify;
var isProd = process.env.NODE_ENV === 'production'; var isProd = process.env.NODE_ENV === 'production';
@ -113,5 +114,8 @@ if (isProd) {
cooking.add('externals.vue-router', 'VueRouter'); cooking.add('externals.vue-router', 'VueRouter');
} }
cooking.add('plugin.CopyWebpackPlugin', new CopyWebpackPlugin([
{ from: 'examples/versions.json' }
]));
cooking.add('vue.preserveWhitespace', false); cooking.add('vue.preserveWhitespace', false);
module.exports = cooking.resolve(); module.exports = cooking.resolve();

View File

@ -2,7 +2,7 @@
<footer class="footer"> <footer class="footer">
<div class="container"> <div class="container">
<div class="footer-main"> <div class="footer-main">
<p class="footer-main-title">Element 1.0 Hydrogen</p> <p class="footer-main-title">Element {{ version }} Hydrogen</p>
<a href="https://github.com/ElemeFE/element/issues" class="footer-main-link" target="_blank">{{ langConfig.feedback }}</a> <a href="https://github.com/ElemeFE/element/issues" class="footer-main-link" target="_blank">{{ langConfig.feedback }}</a>
<a href="https://github.com/ElemeFE/element/blob/master/.github/CONTRIBUTING.md" class="footer-main-link" target="_blank">{{ langConfig.contribution }}</a> <a href="https://github.com/ElemeFE/element/blob/master/.github/CONTRIBUTING.md" class="footer-main-link" target="_blank">{{ langConfig.contribution }}</a>
</div> </div>
@ -134,8 +134,15 @@
<script type="text/babel"> <script type="text/babel">
import compoLang from '../i18n/component.json'; import compoLang from '../i18n/component.json';
import { version } from 'main/index.js';
export default { export default {
data() {
return {
version
};
},
computed: { computed: {
lang() { lang() {
return this.$route.path.split('/')[1]; return this.$route.path.split('/')[1];

View File

@ -12,6 +12,41 @@
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
} }
.nav-dropdown {
margin-bottom: 6px;
width: 100%;
span {
display: block;
width: 100%;
font-size: 16px;
color: #5e6d82;
line-height: 40px;
transition: .2s;
border-bottom: 1px solid #eaeefb;
&:hover {
cursor: pointer;
}
}
i {
transition: .2s;
font-size: 12px;
color: #d3dce6;
}
@when active {
span, i {
color: #20a0ff;
}
i {
transform: rotateZ(180deg) translateY(2px);
}
}
&:hover {
span, i {
color: #20a0ff;
}
}
}
.nav-item { .nav-item {
a { a {
@ -53,9 +88,37 @@
margin-top: 10px; margin-top: 10px;
} }
} }
.nav-dropdown-list {
width: 120px;
margin-top: -8px;
li {
font-size: 14px;
}
}
</style> </style>
<template> <template>
<div class="side-nav" :style="navStyle"> <div class="side-nav" :style="navStyle">
<el-dropdown
v-show="isComponentPage"
trigger="click"
class="nav-dropdown"
:class="{ 'is-active': dropdownVisible }">
<span>
{{ langConfig.dropdown }}{{ version }}
<i class="el-icon-caret-bottom el-icon--right"></i>
</span>
<el-dropdown-menu
slot="dropdown"
:offset="-80"
class="nav-dropdown-list"
@input="handleDropdownToggle">
<el-dropdown-item
v-for="item in Object.keys(versions)"
@click.native="switchVersion(item)">
{{ item }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<ul> <ul>
<li class="nav-item" v-for="item in data"> <li class="nav-item" v-for="item in data">
<a v-if="!item.path" @click="expandMenu">{{item.name}}</a> <a v-if="!item.path" @click="expandMenu">{{item.name}}</a>
@ -99,6 +162,9 @@
</div> </div>
</template> </template>
<script> <script>
import compoLang from '../i18n/component.json';
import { version } from 'main/index.js';
export default { export default {
props: { props: {
data: Array, data: Array,
@ -111,7 +177,10 @@
return { return {
highlights: [], highlights: [],
navState: [], navState: [],
isSmallScreen: false isSmallScreen: false,
versions: [],
version,
dropdownVisible: false
}; };
}, },
watch: { watch: {
@ -122,9 +191,19 @@
computed: { computed: {
navStyle() { navStyle() {
return this.isSmallScreen ? { 'padding-bottom': '60px' } : {}; return this.isSmallScreen ? { 'padding-bottom': '60px' } : {};
},
isComponentPage() {
return /^component-/.test(this.$route.name);
},
langConfig() {
return compoLang.filter(config => config.lang === this.$route.meta.lang)[0]['nav'];
} }
}, },
methods: { methods: {
switchVersion(version) {
if (version === this.version) return;
location.href = `${ location.origin }/${ this.versions[version] }/${ location.hash } `;
},
handleResize() { handleResize() {
this.isSmallScreen = document.documentElement.clientWidth < 768; this.isSmallScreen = document.documentElement.clientWidth < 768;
this.handlePathChange(); this.handlePathChange();
@ -160,8 +239,21 @@
if (!target.nextElementSibling || target.nextElementSibling.tagName !== 'UL') return; if (!target.nextElementSibling || target.nextElementSibling.tagName !== 'UL') return;
this.hideAllMenu(); this.hideAllMenu();
event.currentTarget.nextElementSibling.style.height = 'auto'; event.currentTarget.nextElementSibling.style.height = 'auto';
},
handleDropdownToggle(visible) {
this.dropdownVisible = visible;
} }
}, },
created() {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = _ => {
if (xhr.readyState === 4 && xhr.status === 200) {
this.versions = JSON.parse(xhr.responseText);
}
};
xhr.open('GET', '/versions.json');
xhr.send();
},
mounted() { mounted() {
this.handleResize(); this.handleResize();
window.addEventListener('resize', this.handleResize); window.addEventListener('resize', this.handleResize);

View File

@ -51,7 +51,7 @@ Just edit `element-variables.css`, e.g. changing the theme color to red:
``` ```
### Build theme ### Build theme
After saving the variable file, use `et` to build your theme. You can activate `watch` mode by adding a parameter `-w`: After saving the variable file, use `et` to build your theme. You can activate `watch` mode by adding a parameter `-w`. And if you customized the variable file's output, you need to add a parameter `-c` and variable file's name:
```shell ```shell
et et

View File

@ -256,6 +256,7 @@ Picking a date range is supported.
| disabled | whether DatePicker is disabled | boolean | - | false | | disabled | whether DatePicker is disabled | boolean | - | false |
|size | size of Input | string | large/small/mini | — | |size | size of Input | string | large/small/mini | — |
| editable | whether the input is editable | boolean | - | true | | editable | whether the input is editable | boolean | - | true |
| clearable | Whether to show clear button | boolean | - | true |
| placeholder | placeholder | string | — | — | | placeholder | placeholder | string | — | — |
| type | type of the picker | string | year/month/date/datetime/ week/datetimerange/daterange | date | | type | type of the picker | string | year/month/date/datetime/ week/datetimerange/daterange | date |
| format | format of the picker | string | year `yyyy` month `MM` day `dd`, hour `HH`, minute `mm`, second `ss` | yyyy-MM-dd | | format | format of the picker | string | year `yyyy` month `MM` day `dd`, hour `HH`, minute `mm`, second `ss` | yyyy-MM-dd |
@ -274,4 +275,10 @@ Picking a date range is supported.
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| text | title of the shortcut | string | — | — | | text | title of the shortcut | string | — | — |
| onClick | callback function, triggers when the shortcut is clicked, with the `vm` as its parameter. You can change the picker value by emitting the `pick` event. Example: `vm.$emit('pick', new Date())`| function | — | — | | onClick | callback function, triggers when the shortcut is clicked, with the `vm` as its parameter. You can change the picker value by emitting the `pick` event. Example: `vm.$emit('pick', new Date())`| function | — | — |
### Events
| Event Name | Description | Parameters |
|---------|--------|---------|
| change | triggers when input value changes | formatted value |

View File

@ -210,6 +210,7 @@ Select date and time in one picker.
| readonly | whether DatePicker is read only | boolean | — | false | | readonly | whether DatePicker is read only | boolean | — | false |
| disabled | whether DatePicker is disabled | boolean | - | false | | disabled | whether DatePicker is disabled | boolean | - | false |
| editable | whether the input is editable | boolean | - | true | | editable | whether the input is editable | boolean | - | true |
| clearable | Whether to show clear button | boolean | - | true |
|size | size of Input | string | large/small/mini | — | |size | size of Input | string | large/small/mini | — |
| placeholder | placeholder | string | — | — | | placeholder | placeholder | string | — | — |
| type | type of the picker | string | year/month/date/datetime/ week/datetimerange/daterange | date | | type | type of the picker | string | year/month/date/datetime/ week/datetimerange/daterange | date |
@ -229,3 +230,10 @@ Select date and time in one picker.
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| text | title of the shortcut | string | — | — | | text | title of the shortcut | string | — | — |
| onClick | callback function, triggers when the shortcut is clicked, with the `vm` as its parameter. You can change the picker value by emitting the `pick` event. Example: `vm.$emit('pick', new Date())`| function | — | — | | onClick | callback function, triggers when the shortcut is clicked, with the `vm` as its parameter. You can change the picker value by emitting the `pick` event. Example: `vm.$emit('pick', new Date())`| function | — | — |
### Events
| Event Name | Description | Parameters |
|---------|--------|---------|
| change | triggers when input value changes | formatted value |

View File

@ -3,6 +3,9 @@
methods: { methods: {
handleClick() { handleClick() {
alert('button click'); alert('button click');
},
handleCommand(command) {
this.$message('click on item ' + command);
} }
} }
} }
@ -126,6 +129,36 @@ Use `hide-on-click` to define if menu closes on clicking.
``` ```
::: :::
### Command event
Clicking each dropdown item fires an event whose parameter is assigned by each item.
:::demo
```html
<el-dropdown @command="handleCommand">
<span class="el-dropdown-link">
Dropdown List<i class="el-icon-caret-bottom el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="a">Action 1</el-dropdown-item>
<el-dropdown-item command="b">Action 2</el-dropdown-item>
<el-dropdown-item command="c">Action 3</el-dropdown-item>
<el-dropdown-item command="d" disabled>Action 4</el-dropdown-item>
<el-dropdown-item command="e" divided>Action 5</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<script>
export default {
methods: {
handleCommand(command) {
this.$message('click on item ' + command);
}
}
}
</script>
```
:::
### Dropdown Attributes ### Dropdown Attributes
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |

View File

@ -591,7 +591,10 @@ Search data from server-side.
| Event Name | Description | Parameters | | Event Name | Description | Parameters |
|----| ----| ----| |----| ----| ----|
|click | triggers when the icon inside Input is clicked | event object | |click | triggers when the icon inside Input is clicked | (event: Event) |
| blur | triggers when the icon inside Input is blur | (event: Event) |
| focus | triggers when the icon inside Input is focus | (event: Event) |
| change | triggers when the icon inside Input value change | (value: string \| number) |
### Autocomplete Attributes ### Autocomplete Attributes

View File

@ -1346,6 +1346,94 @@ Customize table column so it can be integrated with other components.
``` ```
::: :::
### Expandable row
When the row content is too long and you do not want to display the horizontal scroll bar, you can use the expandable row feature.
:::demo Activate expandable row by adding type="expand" and `inline-template` attributeThe template for `el-table-column` will be rendered as the contents of the expanded row, you can access the same attributes as the` inline-template`。
```html
<template>
<el-table
:data="tableData3"
style="width: 100%">
<el-table-column type="expand" inline-template>
<div>
<p>State: {{ row.state }}</p>
<p>City: {{ row.city }}</p>
<p>Address: {{ row.address }}</p>
<p>Zip: {{ row.zip }}</p>
</div>
</el-table-column>
<el-table-column
label="Date"
prop="date">
</el-table-column>
<el-table-column
label="Name"
prop="name">
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData3: [{
date: '2016-05-03',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}, {
date: '2016-05-02',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}, {
date: '2016-05-04',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}, {
date: '2016-05-01',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}, {
date: '2016-05-08',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}, {
date: '2016-05-06',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}, {
date: '2016-05-07',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}]
}
}
</script>
```
:::
### Table Attributes ### Table Attributes
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
@ -1361,7 +1449,9 @@ Customize table column so it can be integrated with other components.
| row-style | function that returns custom style for a row, or a string assigning custom style for every row | Function(row, index)/Object | — | — | | row-style | function that returns custom style for a row, or a string assigning custom style for every row | Function(row, index)/Object | — | — |
| row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on | Function(row)/String | — | — | | row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on | Function(row)/String | — | — |
| context | context of Table, e.g. `_self` refers to the current context, `$parent` parent context, `$root` root context, can be overridden by `context` in `el-table-column` | Object | - | current context where Table lies | | context | context of Table, e.g. `_self` refers to the current context, `$parent` parent context, `$root` root context, can be overridden by `context` in `el-table-column` | Object | - | current context where Table lies |
| empty-text | Displayed text when data is empty. You can customize this area with `slot="empty"` | String | | - | No Data | | empty-text | Displayed text when data is empty. You can customize this area with `slot="empty"` | String | - | No Data |
| default-expand-all | whether expand all rows by default, only works when the table has a column type="expand" | Boolean | - | false |
| expand-row-keys | set expanded rows by this prop, prop's value is the keys of expand rows, you should set row-key before using this prop | Array | - | |
| virtual-scrollbar | Enable virtual scrollbar | Boolean | - | false | | virtual-scrollbar | Enable virtual scrollbar | Boolean | - | false |
### Table Events ### Table Events
@ -1380,6 +1470,7 @@ Customize table column so it can be integrated with other components.
| sort-change | triggers when Table's sorting changes | { column, prop, order } | | sort-change | triggers when Table's sorting changes | { column, prop, order } |
| filter-change | column's key. If you need to use the filter-change event, this attribute is mandatory to identify which column is being filtered | filters | | filter-change | column's key. If you need to use the filter-change event, this attribute is mandatory to identify which column is being filtered | filters |
| current-change | triggers when current row changes | currentRow, oldCurrentRow | | current-change | triggers when current row changes | currentRow, oldCurrentRow |
| expand | triggers when user expands or collapses a row | row, expanded |
### Table Methods ### Table Methods
| Method | Description | Parameters | | Method | Description | Parameters |
@ -1390,7 +1481,7 @@ Customize table column so it can be integrated with other components.
### Table-column Attributes ### Table-column Attributes
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| type | type of the column. If set to `selection`, the column will display checkbox. If set to `index`, the column will display index of the row (staring from 1) | string | selection/index | — | | type | type of the column. If set to `selection`, the column will display checkbox. If set to `index`, the column will display index of the row (staring from 1). If set to `expand`, the column will display expand icon. | string | selection/index/expand | — |
| label | column label | string | — | — | | label | column label | string | — | — |
| column-key | column's key. If you need to use the filter-change event, you need this attribute to identify which column is being filtered | string | string | - | - | | column-key | column's key. If you need to use the filter-change event, you need this attribute to identify which column is being filtered | string | string | - | - |
| prop | field name. You can also use its alias: `property` | string | — | — | | prop | field name. You can also use its alias: `property` | string | — | — |
@ -1404,6 +1495,7 @@ Customize table column so it can be integrated with other components.
| formatter | function that formats content | Function(row, column) | — | — | | formatter | function that formats content | Function(row, column) | — | — |
| show-overflow-tooltip | whether to hide extra content and show them in a tooltip when hovering on the cell | boolean | — | false | | show-overflow-tooltip | whether to hide extra content and show them in a tooltip when hovering on the cell | boolean | — | false |
| align | alignment | string | left/center/right | left | | align | alignment | string | left/center/right | left |
| header-align | alignment of the table header. If omitted, the value of the above `align` attribute will be applied | String | left/center/right | — |
| class-name | class name of cells in the column | string | — | — | | class-name | class name of cells in the column | string | — | — |
| selectable | function that determines if a certain row can be selected, works when `type` is 'selection' | Function(row, index) | — | — | | selectable | function that determines if a certain row can be selected, works when `type` is 'selection' | Function(row, index) | — | — |
| reserve-selection | whether to reserve selection after data refreshing, works when `type` is 'selection' | boolean | — | false | | reserve-selection | whether to reserve selection after data refreshing, works when `type` is 'selection' | boolean | — | false |

View File

@ -2,7 +2,18 @@
export default { export default {
data() { data() {
return { return {
activeName: 'first' activeName: 'first',
activeName2: 'first',
tabs: [{
title: 'Tab 1',
name: '1',
content: 'Tab 1 content'
}, {
title: 'Tab 2',
name: '2',
content: 'Tab 2 content'
}],
tabIndex: 2
} }
}, },
methods: { methods: {
@ -11,6 +22,9 @@
}, },
handleClick(tab, event) { handleClick(tab, event) {
console.log(tab, event); console.log(tab, event);
},
renderTab(h, tab) {
return <span><i class="el-icon-date"></i> {tab.label}</span>;
} }
} }
} }
@ -24,11 +38,11 @@ Divide data collections which are related yet belong to different types.
Basic and concise tabs. Basic and concise tabs.
:::demo Tabs provide a selective card functionality and it can be achieved by just using `el-tabs` and child element `el-tab-pane`. In these two elements, we provide a list of attributes. The `label` in `el-tab-pane` determines the label of selective cards, and you can write content in the label. In this example, we add a `active-name` attribute indicating the active card in `el-tabs`, which can take a `String` value. In the `el-tab-pane` you can set corresponding `name` attribute, and if there is no `name`, the default sequence is `1`/`2`/`3`/`4`. In this example, the selected card is card 2. If `name` is omitted, setting `active-name` to `2` can reach the same goal. :::demo Tabs provide a selective card functionality. By default the first tab is selected as active, and you can activate any tab by setting the `value` attribute.
```html ```html
<template> <template>
<el-tabs :active-name="activeName"> <el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="User" name="first">User</el-tab-pane> <el-tab-pane label="User" name="first">User</el-tab-pane>
<el-tab-pane label="Config" name="second">Config</el-tab-pane> <el-tab-pane label="Config" name="second">Config</el-tab-pane>
<el-tab-pane label="Role" name="third">Role</el-tab-pane> <el-tab-pane label="Role" name="third">Role</el-tab-pane>
@ -41,6 +55,11 @@ Basic and concise tabs.
return { return {
activeName: 'first' activeName: 'first'
}; };
},
methods: {
handleClick(tab, event) {
console.log(tab, event);
}
} }
}; };
</script> </script>
@ -55,7 +74,7 @@ Tabs styled as cards.
```html ```html
<template> <template>
<el-tabs type="card" @tab-click="handleClick" @tab-remove="handleRemove"> <el-tabs type="card" @tab-click="handleClick">
<el-tab-pane label="User">User</el-tab-pane> <el-tab-pane label="User">User</el-tab-pane>
<el-tab-pane label="Config">Config</el-tab-pane> <el-tab-pane label="Config">Config</el-tab-pane>
<el-tab-pane label="Role">Role</el-tab-pane> <el-tab-pane label="Role">Role</el-tab-pane>
@ -64,10 +83,12 @@ Tabs styled as cards.
</template> </template>
<script> <script>
export default { export default {
data() {
return {
activeName: 'first'
};
},
methods: { methods: {
handleRemove(tab) {
console.log(tab);
},
handleClick(tab, event) { handleClick(tab, event) {
console.log(tab, event); console.log(tab, event);
} }
@ -81,7 +102,7 @@ Tabs styled as cards.
Closable tabs. Closable tabs.
:::demo You can set `closable` attribute in `el-tabs`. It accept `Boolean` and Tab will be closable when the boolean is `true`. :::demo You can set the closable attribute in el-tabs to make all tabs closable. Also, closable can be set in a tab panel to make that specific tab closable.
```html ```html
<template> <template>
@ -125,12 +146,37 @@ Border card tabs.
::: :::
### Custom Tab
You can use `label-content` property to customize the tab
:::demo `label-content` is a render function,which return the vnode of the tab.
```html
<el-tabs type="border-card">
<el-tab-pane label="Route" :label-content="renderTab">Route</el-tab-pane>
<el-tab-pane label="Config">Config</el-tab-pane>
<el-tab-pane label="Role">Role</el-tab-pane>
<el-tab-pane label="Task">Task</el-tab-pane>
</el-tabs>
<script>
export default {
methods: {
renderTab(h, tab) {
return <span><i class="el-icon-date"></i> {tab.label}</span>;
}
}
}
</script>
```
:::
### Tabs Attributes ### Tabs Attributes
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |
|---------- |-------- |---------- |------------- |-------- | |---------- |-------- |---------- |------------- |-------- |
| type | type of Tab | string | card/border-card | — | | type | type of Tab | string | card/border-card | — |
| closable | whether Tab is closable | boolean | — | false | | closable | whether Tab is closable | boolean | — | false |
| active-name | name of the selected tab | string | — | name of first tab | | active-name(deprecated) | name of the selected tab | string | — | name of first tab |
| value | name of the selected tab | string | — | name of first tab |
### Tabs Events ### Tabs Events
| Event Name | Description | Parameters | | Event Name | Description | Parameters |
@ -145,3 +191,4 @@ Border card tabs.
| label-content | render function for tab title | Function(h, tab:vueInstance) | - | - | | label-content | render function for tab title | Function(h, tab:vueInstance) | - | - |
| disabled | whether Tab is disabled | boolean | - | false | | disabled | whether Tab is disabled | boolean | - | false |
| name | identifier corresponding to the activeName of Tabs, representing the alias of the tab-pane | string | — | ordinal number of the tab-pane in the sequence, i.e. the first tab-pane is '1' | | name | identifier corresponding to the activeName of Tabs, representing the alias of the tab-pane | string | — | ordinal number of the tab-pane in the sequence, i.e. the first tab-pane is '1' |
| closable | whether Tab is closable | boolean | — | false |

View File

@ -146,7 +146,8 @@ Can pick an arbitrary time range.
| readonly | whether DatePicker is read only | boolean | — | false | | readonly | whether DatePicker is read only | boolean | — | false |
| disabled | whether DatePicker is disabled | boolean | - | false | | disabled | whether DatePicker is disabled | boolean | - | false |
| editable | whether the input is editable | boolean | - | true | | editable | whether the input is editable | boolean | - | true |
|size | size of Input | string | large/small/mini | — | | clearable | Whether to show clear button | boolean | - | true |
| size | size of Input | string | large/small/mini | — |
| placeholder | placeholder | string | — | — | | placeholder | placeholder | string | — | — |
| format | format of the picker | string | hour `HH`, minute `mm`, second `ss` | HH:mm:ss | | format | format of the picker | string | hour `HH`, minute `mm`, second `ss` | HH:mm:ss |
| value | value of the picker | date for Time Picker, and string for Time Select | hour `HH`, minute `mm`, second `ss` | HH:mm:ss | | value | value of the picker | date for Time Picker, and string for Time Select | hour `HH`, minute `mm`, second `ss` | HH:mm:ss |
@ -167,3 +168,10 @@ Can pick an arbitrary time range.
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| selectableRange | available time range, e.g.`'18:30:00 - 20:30:00'`or`['09:30:00 - 12:00:00', '14:30:00 - 18:30:00']` | string/array | — | — | | selectableRange | available time range, e.g.`'18:30:00 - 20:30:00'`or`['09:30:00 - 12:00:00', '14:30:00 - 18:30:00']` | string/array | — | — |
### Events
| Event Name | Description | Parameters |
|---------|--------|---------|
| change | triggers when input value changes | formatted value |

View File

@ -51,7 +51,7 @@ et -i [可以自定义变量文件]
``` ```
### 编译主题 ### 编译主题
保存文件后,到命令行里执行 `et` 编译主题,如果你想启用 `watch` 模式,实时编译主题,增加 `-w` 参数 保存文件后,到命令行里执行 `et` 编译主题,如果你想启用 `watch` 模式,实时编译主题,增加 `-w` 参数;如果你在初始化时指定了自定义变量文件,则需要增加 `-c` 参数,并带上你的变量文件名
```shell ```shell
et et

View File

@ -289,6 +289,7 @@
| readonly | 完全只读 | boolean | — | false | | readonly | 完全只读 | boolean | — | false |
| disabled | 禁用 | boolean | - | false | | disabled | 禁用 | boolean | - | false |
| editable | 文本框可输入 | boolean | - | true | | editable | 文本框可输入 | boolean | - | true |
| clearable | 是否显示清除按钮 | boolean | - | true |
| size | 输入框尺寸 | string | large, small, mini | — | | size | 输入框尺寸 | string | large, small, mini | — |
| placeholder | 占位内容 | string | — | — | | placeholder | 占位内容 | string | — | — |
| type | 显示类型 | string | year/month/date/week/ datetime/datetimerange/daterange | date | | type | 显示类型 | string | year/month/date/week/ datetime/datetimerange/daterange | date |
@ -309,3 +310,9 @@
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| text | 标题文本 | string | — | — | | text | 标题文本 | string | — | — |
| onClick | 选中后的回调函数,参数是 vm可通过触发 'pick' 事件设置选择器的值。例如 vm.$emit('pick', new Date()) | function | — | — | | onClick | 选中后的回调函数,参数是 vm可通过触发 'pick' 事件设置选择器的值。例如 vm.$emit('pick', new Date()) | function | — | — |
### Events
| Event Name | Description | Parameters |
|---------|--------|---------|
| change | 当 input 的值改变时触发,返回值和文本框一致 | formatted value |

View File

@ -233,6 +233,7 @@
| readonly | 完全只读 | boolean | — | false | | readonly | 完全只读 | boolean | — | false |
| disabled | 禁用 | boolean | - | false | | disabled | 禁用 | boolean | - | false |
| editable | 文本框可输入 | boolean | - | true | | editable | 文本框可输入 | boolean | - | true |
| clearable | 是否显示清除按钮 | boolean | - | true |
| size | 输入框尺寸 | string | large, small, mini | — | | size | 输入框尺寸 | string | large, small, mini | — |
| placeholder | 占位内容 | string | — | — | | placeholder | 占位内容 | string | — | — |
| type | 显示类型 | string | year/month/date/week/ datetime/datetimerange/daterange | date | | type | 显示类型 | string | year/month/date/week/ datetime/datetimerange/daterange | date |
@ -254,3 +255,9 @@
| onClick | 选中后的回调函数,参数是 vm可通过触发 'pick' 事件设置选择器的值。例如 vm.$emit('pick', new Date()) | function | — | — | | onClick | 选中后的回调函数,参数是 vm可通过触发 'pick' 事件设置选择器的值。例如 vm.$emit('pick', new Date()) | function | — | — |
### Events
| Event Name | Description | Parameters |
|---------|--------|---------|
| change | 当 input 的值改变时触发,返回值和文本框一致 | formatted value |

View File

@ -43,6 +43,9 @@
methods: { methods: {
handleClick() { handleClick() {
alert('button click'); alert('button click');
},
handleCommand(command) {
this.$message('click on item ' + command);
} }
} }
} }
@ -168,6 +171,35 @@
``` ```
::: :::
### 指令事件
点击菜单项后会触发事件,用户可以通过相应的菜单项 key 进行不同的操作
:::demo
```html
<el-dropdown @command="handleCommand">
<span class="el-dropdown-link">
下拉菜单<i class="el-icon-caret-bottom el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="a">黄金糕</el-dropdown-item>
<el-dropdown-item command="b">狮子头</el-dropdown-item>
<el-dropdown-item command="c">螺蛳粉</el-dropdown-item>
<el-dropdown-item command="d" disabled>双皮奶</el-dropdown-item>
<el-dropdown-item command="e" divided>蚵仔煎</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<script>
export default {
methods: {
handleCommand(command) {
this.$message('click on item ' + command);
}
}
}
</script>
```
:::
### Dropdown Attributes ### Dropdown Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |

View File

@ -803,7 +803,7 @@
|---------- |-------------- | |---------- |-------------- |
| validate(cb) | 对整个表单进行校验的方法 | | validate(cb) | 对整个表单进行校验的方法 |
| validateField(prop, cb) | 对部分表单字段进行校验的方法 | | validateField(prop, cb) | 对部分表单字段进行校验的方法 |
| resetFields | 对整个表单进行重置,将所有字段值重置为并移除校验结果 | | resetFields | 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 |
### Form-Item Attributes ### Form-Item Attributes

View File

@ -203,9 +203,7 @@
::: demo ::: demo
```html ```html
<el-input <el-input v-model="input" placeholder="请输入内容">
placeholder="请输入内容"
v-model="input">
</el-input> </el-input>
<script> <script>
@ -759,9 +757,10 @@ export default {
### Input Events ### Input Events
| 事件名称 | 说明 | 回调参数 | | 事件名称 | 说明 | 回调参数 |
|---------|--------|---------| |---------|--------|---------|
| click | 点击 Input 内的图标时触发 | event | | click | 点击 Input 内的图标时触发 | (event: Event) |
| blur | 在 Input 失去焦点时触发 | event | | blur | 在 Input 失去焦点时触发 | (event: Event) |
| focus | 在 Input 或得焦点时触发 | event | | focus | 在 Input 或得焦点时触发 | (event: Event) |
| change | 在 Input 值改变时触发 | (value: string \| number) |
### Autocomplete Attributes ### Autocomplete Attributes

View File

@ -60,6 +60,7 @@
province: '上海', province: '上海',
city: '普陀区', city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄', address: '上海市普陀区金沙江路 1518 弄',
detailAddress: '金沙江路 1518 弄',
zip: 200333 zip: 200333
}, { }, {
date: '2016-05-02', date: '2016-05-02',
@ -67,6 +68,7 @@
province: '上海', province: '上海',
city: '普陀区', city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄', address: '上海市普陀区金沙江路 1518 弄',
detailAddress: '金沙江路 1518 弄',
zip: 200333 zip: 200333
}, { }, {
date: '2016-05-04', date: '2016-05-04',
@ -81,6 +83,7 @@
province: '上海', province: '上海',
city: '普陀区', city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄', address: '上海市普陀区金沙江路 1518 弄',
detailAddress: '金沙江路 1518 弄',
zip: 200333 zip: 200333
}, { }, {
date: '2016-05-08', date: '2016-05-08',
@ -88,6 +91,7 @@
province: '上海', province: '上海',
city: '普陀区', city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄', address: '上海市普陀区金沙江路 1518 弄',
detailAddress: '金沙江路 1518 弄',
zip: 200333 zip: 200333
}, { }, {
date: '2016-05-06', date: '2016-05-06',
@ -95,6 +99,7 @@
province: '上海', province: '上海',
city: '普陀区', city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄', address: '上海市普陀区金沙江路 1518 弄',
detailAddress: '金沙江路 1518 弄',
zip: 200333 zip: 200333
}, { }, {
date: '2016-05-07', date: '2016-05-07',
@ -102,6 +107,7 @@
province: '上海', province: '上海',
city: '普陀区', city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄', address: '上海市普陀区金沙江路 1518 弄',
detailAddress: '金沙江路 1518 弄',
zip: 200333 zip: 200333
}], }],
tableData4: [{ tableData4: [{
@ -1354,6 +1360,74 @@
``` ```
::: :::
### 展开行
当行内容过多并且不想显示横向滚动条时,可以使用 Table 展开行功能。
:::demo 通过设置 type="expand" 和 `inline-template` 属性可以开启展开行功能,`el-table-column` 的模板会被渲染成为展开行的内容,展开行可访问的属性与使用 `inline-template` 的时候相同。
```html
<template>
<el-table
:data="tableData3"
style="width: 100%">
<el-table-column type="expand" inline-template>
<div>
<p>省: {{ row.province }}</p>
<p>市: {{ row.city }}</p>
<p>住址: {{ row.detailAddress }}</p>
<p>邮编: {{ row.zip }}</p>
</div>
</el-table-column>
<el-table-column
label="日期"
prop="date">
</el-table-column>
<el-table-column
label="姓名"
prop="name">
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData3: [{
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
detailAddress: '金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
detailAddress: '金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
detailAddress: '金沙江路 1518 弄',
zip: 200333
}, {
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
detailAddress: '金沙江路 1518 弄',
zip: 200333
}]
}
}
}
</script>
```
:::
### Table Attributes ### Table Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
@ -1368,9 +1442,12 @@
| row-style | 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。 | Function(row, index)/Object | — | — | | row-style | 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。 | Function(row, index)/Object | — | — |
| row-key | 行数据的 Key用来优化 Table 的渲染;在使用 reserve-selection 功能的情况下,该属性是必填的 | Function(row)/String | — | — | | row-key | 行数据的 Key用来优化 Table 的渲染;在使用 reserve-selection 功能的情况下,该属性是必填的 | Function(row)/String | — | — |
| context | 设置上下文环境,例如设置当前上下文就是 `_self`,父级就是 `$parent`,根组件 `$root`。优先读取 column 的 context 属性。 | Object | - | Table 所处上下文 | | context | 设置上下文环境,例如设置当前上下文就是 `_self`,父级就是 `$parent`,根组件 `$root`。优先读取 column 的 context 属性。 | Object | - | Table 所处上下文 |
| empty-text | 空数据时显示的文本内容,也可以通过 `slot="empty"` 设置 | String | | - | 暂无数据 | | empty-text | 空数据时显示的文本内容,也可以通过 `slot="empty"` 设置 | String | - | 暂无数据 |
| default-expand-all | 是否默认展开所有行,当 Table 中存在 type="expand" 的 Column 的时候有效 | Boolean | - | false |
| expand-row-keys | 可以通过该属性设置 Table 目前的展开行,需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组。| Array | - | |
| virtual-scrollbar | 启用虚拟滚动条 | Boolean | - | false | | virtual-scrollbar | 启用虚拟滚动条 | Boolean | - | false |
### Table Events ### Table Events
| 事件名 | 说明 | 参数 | | 事件名 | 说明 | 参数 |
| ---- | ---- | ---- | | ---- | ---- | ---- |
@ -1387,6 +1464,7 @@
| sort-change | 当表格的排序条件发生变化的时候会触发该事件 | { column, prop, order } | | sort-change | 当表格的排序条件发生变化的时候会触发该事件 | { column, prop, order } |
| filter-change | 当表格的筛选条件发生变化的时候会触发该事件,参数的值是一个对象,对象的 key 是 column 的 columnKey对应的 value 为用户选择的筛选条件的数组。 | filters | | filter-change | 当表格的筛选条件发生变化的时候会触发该事件,参数的值是一个对象,对象的 key 是 column 的 columnKey对应的 value 为用户选择的筛选条件的数组。 | filters |
| current-change | 当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性 | currentRow, oldCurrentRow | | current-change | 当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性 | currentRow, oldCurrentRow |
| expand | 当用户对某一行展开或者关闭的上会触发该事件 | row, expanded |
### Table Methods ### Table Methods
| 方法名 | 说明 | 参数 | | 方法名 | 说明 | 参数 |
@ -1397,7 +1475,7 @@
### Table-column Attributes ### Table-column Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| type | 对应列的类型。如果设置了 `selection` 则显示多选框如果设置了 `index` 则显示该行的索引(从 1 开始计算) | string | selection/index | — | | type | 对应列的类型。如果设置了 `selection` 则显示多选框如果设置了 `index` 则显示该行的索引(从 1 开始计算);如果设置了 expand 则显示为一个可展开的按钮 | string | selection/index/expand | — |
| column-key | column 的 key如果需要使用 filter-change 事件,则需要此属性标识是哪个 column 的筛选条件 | string | - | - | | column-key | column 的 key如果需要使用 filter-change 事件,则需要此属性标识是哪个 column 的筛选条件 | string | - | - |
| label | 显示的标题 | string | — | — | | label | 显示的标题 | string | — | — |
| prop | 对应列内容的字段名,也可以使用 property 属性 | string | — | — | | prop | 对应列内容的字段名,也可以使用 property 属性 | string | — | — |
@ -1410,7 +1488,8 @@
| resizable | 对应列是否可以通过拖动改变宽度(需要在 el-table 上设置 border 属性为真) | boolean | — | true | | resizable | 对应列是否可以通过拖动改变宽度(需要在 el-table 上设置 border 属性为真) | boolean | — | true |
| formatter | 用来格式化内容 | Function(row, column) | — | — | | formatter | 用来格式化内容 | Function(row, column) | — | — |
| show-overflow-tooltip | 当内容过长被隐藏时显示 tooltip | Boolean | — | false | | show-overflow-tooltip | 当内容过长被隐藏时显示 tooltip | Boolean | — | false |
| align | 对齐方式 | String | left, center, right | left | | align | 对齐方式 | String | left/center/right | left |
| header-align | 表头对齐方式,若不设置该项,则使用表格的对齐方式 | String | left/center/right | — |
| class-name | 列的 className | string | — | — | | class-name | 列的 className | string | — | — |
| selectable | 仅对 type=selection 的列有效,类型为 FunctionFunction 的返回值用来决定这一行的 CheckBox 是否可以勾选 | Function(row, index) | — | — | | selectable | 仅对 type=selection 的列有效,类型为 FunctionFunction 的返回值用来决定这一行的 CheckBox 是否可以勾选 | Function(row, index) | — | — |
| reserve-selection | 仅对 type=selection 的列有效,类型为 Boolean为 true 则代表会保留之前数据的选项,需要配合 Table 的 clearSelection 方法使用。 | Boolean | — | false | | reserve-selection | 仅对 type=selection 的列有效,类型为 Boolean为 true 则代表会保留之前数据的选项,需要配合 Table 的 clearSelection 方法使用。 | Boolean | — | false |

View File

@ -2,7 +2,18 @@
export default { export default {
data() { data() {
return { return {
activeName: 'first' activeName: 'first',
activeName2: 'first',
tabs: [{
title: 'Tab 1',
name: '1',
content: 'Tab 1 content'
}, {
title: 'Tab 2',
name: '2',
content: 'Tab 2 content'
}],
tabIndex: 2
} }
}, },
methods: { methods: {
@ -11,22 +22,27 @@
}, },
handleClick(tab, event) { handleClick(tab, event) {
console.log(tab, event); console.log(tab, event);
},
renderTab(h, tab) {
return <span><i class="el-icon-date"></i> {tab.label}</span>;
} }
} }
} }
</script> </script>
## Tabs 标签页 ## Tabs 标签页
分隔内容上有关联但属于不同类别的数据集合。 分隔内容上有关联但属于不同类别的数据集合。
### 基础用法 ### 基础用法
基础的、简洁的标签页。 基础的、简洁的标签页。
:::demo Tabs 组件提供了选项卡功能,只需要使用`el-tabs`和子元素`el-tab-pane`即可,在两个元素中,我们分别提供了一系列的属性来方便使用,`el-tab-pane`中`label`决定了选项卡标题,标签内部写入内容即可。在下例中我们在`el-tabs`中设置了`active-name`属性,接受一个`String`值,表明选中的选项卡,在`el-tab-pane`中可以设置对应的`name`属性,如果没有设置`name`,则默认值为顺序的`1`/`2`/`3`/`4`。例子选中选项卡2如果不设置`name`,将`active-name`设为`2`,可以达成相同效果 :::demo Tabs 组件提供了选项卡功能,默认选中第一个标签页,你也可以通过 `value` 属性来指定当前选中的标签页
```html ```html
<template> <template>
<el-tabs :active-name="activeName"> <el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="用户管理" name="first">用户管理</el-tab-pane> <el-tab-pane label="用户管理" name="first">用户管理</el-tab-pane>
<el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane> <el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane>
<el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane> <el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane>
@ -39,6 +55,11 @@
return { return {
activeName: 'first' activeName: 'first'
}; };
},
methods: {
handleClick(tab, event) {
console.log(tab, event);
}
} }
}; };
</script> </script>
@ -49,23 +70,25 @@
选项卡样式的标签页。 选项卡样式的标签页。
:::demo 只需要设置`type`属性即可,如果需要标签风格,将其设置为`card`。 :::demo 只需要设置 `type` 属性为 `card` 就可以使选项卡改变为标签风格
```html ```html
<template> <template>
<el-tabs type="card" @tab-click="handleClick" @tab-remove="handleRemove"> <el-tabs v-model="activeName2" type="card" @tab-click="handleClick">
<el-tab-pane label="用户管理">用户管理</el-tab-pane> <el-tab-pane label="用户管理" name="first">用户管理</el-tab-pane>
<el-tab-pane label="配置管理">配置管理</el-tab-pane> <el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane>
<el-tab-pane label="角色管理">角色管理</el-tab-pane> <el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane>
<el-tab-pane label="定时任务补偿">定时任务补偿</el-tab-pane> <el-tab-pane label="定时任务补偿" name="fourth">定时任务补偿</el-tab-pane>
</el-tabs> </el-tabs>
</template> </template>
<script> <script>
export default { export default {
data() {
return {
activeName: 'first'
};
},
methods: { methods: {
handleRemove(tab) {
console.log(tab);
},
handleClick(tab, event) { handleClick(tab, event) {
console.log(tab, event); console.log(tab, event);
} }
@ -79,11 +102,11 @@
可以关闭标签页。 可以关闭标签页。
:::demo 在`el-tabs`中设置`closable`属性,接受一个`Boolean`,设置为`true`时为可关闭 :::demo 通过设置 `closable` 属性来打开 `Tabs` 的可关闭标签效果, `closable` 也可以设置在 `Tab Panel` 中实现部分标签页的可关闭效果
```html ```html
<template> <template>
<el-tabs type="card" :closable="true" @tab-click="handleClick" @tab-remove="handleRemove"> <el-tabs type="card" closable @tab-click="handleClick" @tab-remove="handleRemove">
<el-tab-pane label="用户管理">用户管理</el-tab-pane> <el-tab-pane label="用户管理">用户管理</el-tab-pane>
<el-tab-pane label="配置管理">配置管理</el-tab-pane> <el-tab-pane label="配置管理">配置管理</el-tab-pane>
<el-tab-pane label="角色管理">角色管理</el-tab-pane> <el-tab-pane label="角色管理">角色管理</el-tab-pane>
@ -120,12 +143,52 @@
``` ```
::: :::
### 自定义标签页
可以通过 `label-content` 属性来实现自定义标签页的内容
:::demo `label-content` 是一个 render function在这个方法里返回的 vnode 会被渲染到标签页中。
```html
<el-tabs type="border-card">
<el-tab-pane label="我的行程" :label-content="renderTab">我的行程</el-tab-pane>
<el-tab-pane label="消息中心">消息中心</el-tab-pane>
<el-tab-pane label="角色管理">角色管理</el-tab-pane>
<el-tab-pane label="定时任务补偿">定时任务补偿</el-tab-pane>
</el-tabs>
<script>
export default {
methods: {
renderTab(h, tab) {
return <span><i class="el-icon-date"></i> {tab.label}</span>;
}
}
}
</script>
```
:::
### 动态增加标签页
展示如何通过触发器来动态增加标签页
:::demo
```html
<div style="margin-bottom: 20px;">
<el-button size="small" @click="tabs.push({ name: 'Tab ' + ++tabIndex, title: 'new Tab', content: 'new Tab content' })">add tab</el-button>
</div>
<el-tabs type="card" closable>
<el-tab-pane v-for="(item, index) in tabs" :label="item.title" :name="item.name">{{item.content}}</el-tab-pane>
</el-tabs>
```
:::
### Tabs Attributes ### Tabs Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------- |-------- |---------- |------------- |-------- | |---------- |-------- |---------- |------------- |-------- |
| type | 风格类型 | string | card/border-card | — | | type | 风格类型 | string | card/border-card | — |
| closable | 标签是否可关闭 | boolean | — | false | | closable | 标签是否可关闭 | boolean | — | false |
| active-name | 选中选项卡的 name | string | — | 第一个选项卡的 name | | active-name(deprecated) | 选中选项卡的 name | string | — | 第一个选项卡的 name |
| value | 绑定值,选中选项卡的 name | string | — | 第一个选项卡的 name |
### Tabs Events ### Tabs Events
| 事件名称 | 说明 | 回调参数 | | 事件名称 | 说明 | 回调参数 |
@ -140,3 +203,4 @@
| label-content | 选项卡的标题的渲染 Function | Function(h, tab:vueInstance) | - | - | | label-content | 选项卡的标题的渲染 Function | Function(h, tab:vueInstance) | - | - |
| disabled | 是否禁用 | boolean | - | false | | disabled | 是否禁用 | boolean | - | false |
| name | 与选项卡 activeName 对应的标识符,表示选项卡别名 | string | — | 该选项卡在选项卡列表中的顺序值,如第一个选项卡则为'1' | | name | 与选项卡 activeName 对应的标识符,表示选项卡别名 | string | — | 该选项卡在选项卡列表中的顺序值,如第一个选项卡则为'1' |
| closable | 标签是否可关闭 | boolean | — | false |

View File

@ -153,6 +153,7 @@
| readonly | 完全只读 | boolean | — | false | | readonly | 完全只读 | boolean | — | false |
| disabled | 禁用 | boolean | - | false | | disabled | 禁用 | boolean | - | false |
| editable | 文本框可输入 | boolean | - | true | | editable | 文本框可输入 | boolean | - | true |
| clearable | 是否显示清除按钮 | boolean | - | true |
| size | 输入框尺寸 | string | large, small, mini | — | | size | 输入框尺寸 | string | large, small, mini | — |
| placeholder | 占位内容 | string | — | — | | placeholder | 占位内容 | string | — | — |
| format | 时间格式化(TimePicker) | string | 小时:`HH`,分:`mm`,秒:`ss` | 'HH:mm:ss' | | format | 时间格式化(TimePicker) | string | 小时:`HH`,分:`mm`,秒:`ss` | 'HH:mm:ss' |
@ -175,3 +176,11 @@
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| selectableRange | 可选时间段,例如`'18:30:00 - 20:30:00'`或者传入数组`['09:30:00 - 12:00:00', '14:30:00 - 18:30:00']` | string/array | — | — | | selectableRange | 可选时间段,例如`'18:30:00 - 20:30:00'`或者传入数组`['09:30:00 - 12:00:00', '14:30:00 - 18:30:00']` | string/array | — | — |
### Events
| Event Name | Description | Parameters |
|---------|--------|---------|
| change | 当 input 的值改变时触发,返回值和文本框一致 | formatted value |

View File

@ -16,6 +16,9 @@
"guide": "指南", "guide": "指南",
"components": "组件", "components": "组件",
"resource": "资源" "resource": "资源"
},
"nav": {
"dropdown": "版本:"
} }
}, },
{ {
@ -35,6 +38,9 @@
"guide": "Guide", "guide": "Guide",
"components": "Component", "components": "Component",
"resource": "Resource" "resource": "Resource"
},
"nav": {
"dropdown": "Version: "
} }
} }
] ]

3
examples/versions.json Normal file
View File

@ -0,0 +1,3 @@
{
"1.0.9": "1.0"
}

View File

@ -1,6 +1,6 @@
{ {
"name": "element-ui", "name": "element-ui",
"version": "1.0.8", "version": "1.0.9",
"description": "A Component Library for Vue.js.", "description": "A Component Library for Vue.js.",
"main": "lib/element-ui.common.js", "main": "lib/element-ui.common.js",
"files": [ "files": [
@ -58,13 +58,14 @@
"babel-loader": "^6.2.5", "babel-loader": "^6.2.5",
"babel-plugin-module-resolver": "^2.2.0", "babel-plugin-module-resolver": "^2.2.0",
"babel-plugin-syntax-jsx": "^6.8.0", "babel-plugin-syntax-jsx": "^6.8.0",
"babel-plugin-transform-vue-jsx": "^3.1.0", "babel-plugin-transform-vue-jsx": "^3.3.0",
"babel-preset-es2015": "^6.14.0", "babel-preset-es2015": "^6.14.0",
"chai": "^3.5.0", "chai": "^3.5.0",
"cheerio": "^0.18.0", "cheerio": "^0.18.0",
"cooking": "^1.2.0", "cooking": "^1.2.0",
"cooking-lint": "^0.1.3", "cooking-lint": "^0.1.3",
"cooking-vue2": "^0.3.0", "cooking-vue2": "^0.3.0",
"copy-webpack-plugin": "^4.0.1",
"coveralls": "^2.11.14", "coveralls": "^2.11.14",
"cp-cli": "^1.0.2", "cp-cli": "^1.0.2",
"cross-env": "^3.1.3", "cross-env": "^3.1.3",

View File

@ -1,14 +1,14 @@
<template> <template>
<label class="el-checkbox"> <label class="el-checkbox">
<span class="el-checkbox__input"> <span class="el-checkbox__input"
<span class="el-checkbox__inner" :class="{
:class="{ 'is-disabled': disabled,
'is-disabled': disabled, 'is-checked': isChecked,
'is-checked': isChecked, 'is-indeterminate': indeterminate,
'is-indeterminate': indeterminate, 'is-focus': focus
'is-focus': focus }"
}" >
></span> <span class="el-checkbox__inner"></span>
<input <input
v-if="trueLabel || falseLabel" v-if="trueLabel || falseLabel"
class="el-checkbox__original" class="el-checkbox__original"

View File

@ -293,7 +293,7 @@
handleClear() { handleClear() {
this.minDate = null; this.minDate = null;
this.maxDate = null; this.maxDate = null;
this.handleConfirm(); this.handleConfirm(false);
}, },
handleDateInput(event, type) { handleDateInput(event, type) {
@ -376,10 +376,8 @@
this.maxDate = val.maxDate; this.maxDate = val.maxDate;
this.minDate = val.minDate; this.minDate = val.minDate;
if (!close) return; if (!close || this.showTime) return;
if (!this.showTime) { this.handleConfirm();
this.$emit('pick', [this.minDate, this.maxDate]);
}
}, },
changeToToday() { changeToToday() {
@ -456,7 +454,7 @@
this.resetDate(); this.resetDate();
}, },
handleConfirm(visible) { handleConfirm(visible = false) {
this.$emit('pick', [this.minDate, this.maxDate], visible); this.$emit('pick', [this.minDate, this.maxDate], visible);
}, },

View File

@ -190,7 +190,7 @@
methods: { methods: {
handleClear() { handleClear() {
this.date = new Date(); this.date = new Date();
this.$emit('pick', ''); this.$emit('pick');
}, },
resetDate() { resetDate() {

View File

@ -92,7 +92,7 @@
}, },
handleClear() { handleClear() {
this.$emit('pick', ''); this.$emit('pick');
} }
}, },

View File

@ -104,7 +104,7 @@
methods: { methods: {
handleClear() { handleClear() {
this.$emit('pick', ''); this.$emit('pick');
}, },
handleCancel() { handleCancel() {

View File

@ -26,7 +26,7 @@
<script> <script>
import Vue from 'vue'; import Vue from 'vue';
import Clickoutside from 'element-ui/src/utils/clickoutside'; import Clickoutside from 'element-ui/src/utils/clickoutside';
import { formatDate, parseDate, getWeekNumber } from './util'; import { formatDate, parseDate, getWeekNumber, equalDate } from './util';
import Popper from 'element-ui/src/utils/vue-popper'; import Popper from 'element-ui/src/utils/vue-popper';
import Emitter from 'element-ui/src/mixins/emitter'; import Emitter from 'element-ui/src/mixins/emitter';
import ElInput from 'element-ui/packages/input'; import ElInput from 'element-ui/packages/input';
@ -187,6 +187,10 @@ export default {
readonly: Boolean, readonly: Boolean,
placeholder: String, placeholder: String,
disabled: Boolean, disabled: Boolean,
clearable: {
type: Boolean,
default: true
},
popperClass: String, popperClass: String,
editable: { editable: {
type: Boolean, type: Boolean,
@ -305,9 +309,10 @@ export default {
if (parsedValue && this.picker) { if (parsedValue && this.picker) {
this.picker.value = parsedValue; this.picker.value = parsedValue;
} }
return; } else {
this.picker.value = value;
} }
this.picker.value = value; this.$forceUpdate();
} }
} }
}, },
@ -324,21 +329,36 @@ export default {
methods: { methods: {
handleMouseEnterIcon() { handleMouseEnterIcon() {
if (this.readonly || this.disabled) return; if (this.readonly || this.disabled) return;
if (!this.valueIsEmpty) { if (!this.valueIsEmpty && this.clearable) {
this.showClose = true; this.showClose = true;
} }
}, },
handleClickIcon() { handleClickIcon() {
if (this.readonly || this.disabled) return; if (this.readonly || this.disabled) return;
if (this.valueIsEmpty) { if (this.showClose) {
this.pickerVisible = !this.pickerVisible;
} else {
this.internalValue = ''; this.internalValue = '';
this.$emit('input', ''); } else {
this.pickerVisible = !this.pickerVisible;
} }
}, },
dateIsUpdated(date) {
let updated = true;
if (Array.isArray(date)) {
if (equalDate(this.cacheDateMin, date[0]) &&
equalDate(this.cacheDateMax, date[1])) updated = false;
this.cacheDateMin = date[0];
this.cacheDateMax = date[1];
} else {
if (equalDate(this.cacheDate, date)) updated = false;
this.cacheDate = date;
}
return updated;
},
handleClose() { handleClose() {
this.pickerVisible = false; this.pickerVisible = false;
}, },
@ -419,7 +439,9 @@ export default {
this.picker.$on('dodestroy', this.doDestroy); this.picker.$on('dodestroy', this.doDestroy);
this.picker.$on('pick', (date, visible = false) => { this.picker.$on('pick', (date, visible = false) => {
this.$emit('input', date); if (this.dateIsUpdated(date)) this.$emit('input', date);
this.$nextTick(() => this.$emit('change', this.visualValue));
this.pickerVisible = this.picker.visible = visible; this.pickerVisible = this.picker.visible = visible;
this.picker.resetView && this.picker.resetView(); this.picker.resetView && this.picker.resetView();
}); });

View File

@ -8,6 +8,10 @@ const newArray = function(start, end) {
return result; return result;
}; };
export const equalDate = function(dateA, dateB) {
return new Date(dateA).getTime() === new Date(dateB).getTime();
};
export const toDate = function(date) { export const toDate = function(date) {
date = new Date(date); date = new Date(date);
if (isNaN(date.getTime())) return null; if (isNaN(date.getTime())) return null;

View File

@ -45,7 +45,7 @@ Vue.component('el-form-item', ElForm)
|---------- |-------------- | |---------- |-------------- |
| validate(cb) | 对整个表单进行校验的方法 | | validate(cb) | 对整个表单进行校验的方法 |
| validateField(prop, cb) | 对部分表单字段进行校验的方法 | | validateField(prop, cb) | 对部分表单字段进行校验的方法 |
| resetFields | 对整个表单进行重置,将所有字段值重置为并移除校验结果 | | resetFields | 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 |
### Form-Item Attributes ### Form-Item Attributes

View File

@ -54,12 +54,13 @@
}, },
validate(callback) { validate(callback) {
let valid = true; let valid = true;
let count = 0;
this.fields.forEach((field, index) => { this.fields.forEach((field, index) => {
field.validate('', errors => { field.validate('', errors => {
if (errors) { if (errors) {
valid = false; valid = false;
} }
if (typeof callback === 'function' && index === this.fields.length - 1) { if (typeof callback === 'function' && ++count === this.fields.length) {
callback(valid); callback(valid);
} }
}); });

View File

@ -6,31 +6,11 @@
{ 'is-without-controls': !controls} { 'is-without-controls': !controls}
]" ]"
> >
<el-input
:value="currentValue"
@keydown.up.native="increase"
@keydown.down.native="decrease"
@blur="handleBlur"
@input="handleInput"
:disabled="disabled"
:size="size"
:class="{
'is-active': inputActive
}">
<template slot="prepend" v-if="$slots.prepend">
<slot name="prepend"></slot>
</template>
<template slot="append" v-if="$slots.append">
<slot name="append"></slot>
</template>
</el-input>
<span <span
v-if="controls" v-if="controls"
class="el-input-number__decrease el-icon-minus" class="el-input-number__decrease el-icon-minus"
:class="{'is-disabled': minDisabled}" :class="{'is-disabled': minDisabled}"
v-repeat-click="decrease" v-repeat-click="decrease"
@mouseenter="activeInput(minDisabled)"
@mouseleave="inactiveInput(minDisabled)"
> >
</span> </span>
<span <span
@ -38,10 +18,24 @@
class="el-input-number__increase el-icon-plus" class="el-input-number__increase el-icon-plus"
:class="{'is-disabled': maxDisabled}" :class="{'is-disabled': maxDisabled}"
v-repeat-click="increase" v-repeat-click="increase"
@mouseenter="activeInput(maxDisabled)"
@mouseleave="inactiveInput(maxDisabled)"
> >
</span> </span>
<el-input
v-model.number="currentValue"
@keydown.up.native="increase"
@keydown.down.native="decrease"
@blur="handleBlur"
:disabled="disabled"
:size="size"
ref="input"
>
<template slot="prepend" v-if="$slots.prepend">
<slot name="prepend"></slot>
</template>
<template slot="append" v-if="$slots.append">
<slot name="append"></slot>
</template>
</el-input>
</div> </div>
</template> </template>
<script> <script>
@ -50,29 +44,6 @@
export default { export default {
name: 'ElInputNumber', name: 'ElInputNumber',
props: {
step: {
type: Number,
default: 1
},
max: {
type: Number,
default: Infinity
},
min: {
type: Number,
default: 0
},
value: {
default: 0
},
disabled: Boolean,
size: String,
controls: {
type: Boolean,
default: true
}
},
directives: { directives: {
repeatClick: { repeatClick: {
bind(el, binding, vnode) { bind(el, binding, vnode) {
@ -99,6 +70,29 @@
components: { components: {
ElInput ElInput
}, },
props: {
step: {
type: Number,
default: 1
},
max: {
type: Number,
default: Infinity
},
min: {
type: Number,
default: 0
},
value: {
default: 0
},
disabled: Boolean,
size: String,
controls: {
type: Boolean,
default: true
}
},
data() { data() {
// correct the init value // correct the init value
let value = this.value; let value = this.value;
@ -111,8 +105,7 @@
value = this.max; value = this.max;
} }
return { return {
currentValue: value, currentValue: value
inputActive: false
}; };
}, },
watch: { watch: {
@ -121,19 +114,18 @@
}, },
currentValue(newVal, oldVal) { currentValue(newVal, oldVal) {
let value = Number(newVal); if (newVal <= this.max && newVal >= this.min) {
if (value <= this.max && value >= this.min) { this.$emit('change', newVal, oldVal);
this.$emit('change', value, oldVal); this.$emit('input', newVal);
this.$emit('input', value);
} }
} }
}, },
computed: { computed: {
minDisabled() { minDisabled() {
return this.value - this.step < this.min; return this.accSub(this.value, this.step) < this.min;
}, },
maxDisabled() { maxDisabled() {
return this.value + this.step > this.max; return this.accAdd(this.value, this.step) > this.max;
} }
}, },
methods: { methods: {
@ -183,41 +175,19 @@
return (arg1 + arg2) / m; return (arg1 + arg2) / m;
}, },
increase() { increase() {
if (this.maxDisabled) return;
const value = this.value || 0; const value = this.value || 0;
if (value + this.step > this.max || this.disabled) return; if (this.accAdd(value, this.step) > this.max || this.disabled) return;
this.currentValue = this.accAdd(this.step, value); this.currentValue = this.accAdd(value, this.step);
if (this.maxDisabled) {
this.inputActive = false;
}
}, },
decrease() { decrease() {
if (this.minDisabled) return;
const value = this.value || 0; const value = this.value || 0;
if (value - this.step < this.min || this.disabled) return; if (this.accSub(value, this.step) < this.min || this.disabled) return;
this.currentValue = this.accSub(value, this.step); this.currentValue = this.accSub(value, this.step);
if (this.minDisabled) {
this.inputActive = false;
}
}, },
activeInput(disabled) { handleBlur() {
if (!this.disabled && !disabled) { this.$refs.input.setCurrentValue(this.currentValue);
this.inputActive = true;
}
},
inactiveInput(disabled) {
if (!this.disabled && !disabled) {
this.inputActive = false;
}
},
handleBlur(event) {
let value = Number(this.currentValue);
if (isNaN(value) || value > this.max || value < this.min) {
this.currentValue = this.value;
} else {
this.currentValue = value;
}
},
handleInput(value) {
this.currentValue = value;
} }
} }
}; };

View File

@ -33,7 +33,7 @@
:min="min" :min="min"
:max="max" :max="max"
:form="form" :form="form"
:value="value" :value="currentValue"
ref="input" ref="input"
@input="handleInput" @input="handleInput"
@focus="handleFocus" @focus="handleFocus"
@ -48,7 +48,8 @@
<textarea <textarea
v-else v-else
class="el-textarea__inner" class="el-textarea__inner"
v-model="currentValue" :value="currentValue"
@input="handleInput"
ref="textarea" ref="textarea"
:name="name" :name="name"
:placeholder="placeholder" :placeholder="placeholder"
@ -76,6 +77,13 @@
mixins: [emitter], mixins: [emitter],
data() {
return {
currentValue: this.value,
textareaStyle: {}
};
},
props: { props: {
value: [String, Number], value: [String, Number],
placeholder: String, placeholder: String,
@ -108,6 +116,18 @@
min: {} min: {}
}, },
computed: {
validating() {
return this.$parent.validateState === 'validating';
}
},
watch: {
'value'(val, oldValue) {
this.setCurrentValue(val);
}
},
methods: { methods: {
handleBlur(event) { handleBlur(event) {
this.$emit('blur', event); this.$emit('blur', event);
@ -129,46 +149,29 @@
this.$emit('focus', event); this.$emit('focus', event);
}, },
handleInput(event) { handleInput(event) {
this.currentValue = event.target.value; this.setCurrentValue(event.target.value);
}, },
handleIconClick(event) { handleIconClick(event) {
this.$emit('click', event); this.$emit('click', event);
},
setCurrentValue(value) {
if (value === this.currentValue) return;
this.$nextTick(_ => {
this.resizeTextarea();
});
this.currentValue = value;
this.$emit('input', value);
this.$emit('change', value);
this.dispatch('ElFormItem', 'el.form.change', [value]);
} }
}, },
data() {
return {
currentValue: this.value,
textareaStyle: {}
};
},
created() { created() {
this.$on('inputSelect', this.inputSelect); this.$on('inputSelect', this.inputSelect);
}, },
mounted() { mounted() {
this.resizeTextarea(); this.resizeTextarea();
},
computed: {
validating() {
return this.$parent.validateState === 'validating';
}
},
watch: {
'value'(val, oldValue) {
this.currentValue = val;
},
'currentValue'(val) {
this.$nextTick(_ => {
this.resizeTextarea();
});
this.$emit('input', val);
this.$emit('change', val);
this.dispatch('ElFormItem', 'el.form.change', [val]);
}
} }
}; };
</script> </script>

View File

@ -107,6 +107,14 @@
}, },
openActiveItemMenus() { openActiveItemMenus() {
let index = this.activeIndex; let index = this.activeIndex;
// menu
if (this.router) {
const userSpecifiedIndexs = Object
.keys(this.menuItems)
.filter(k => this.menuItems[k].route)
.filter(k => this.menuItems[k].route.path === this.$route.path);
userSpecifiedIndexs.length && (index = this.activeIndex = userSpecifiedIndexs[0]);
}
if (!this.menuItems[index]) return; if (!this.menuItems[index]) return;
if (index && this.mode === 'vertical') { if (index && this.mode === 'vertical') {
let indexPath = this.menuItems[index].indexPath; let indexPath = this.menuItems[index].indexPath;

View File

@ -100,6 +100,7 @@ export default {
render(h) { render(h) {
return ( return (
<button <button
type="button"
class={['btn-prev', { disabled: this.$parent.internalCurrentPage <= 1 }]} class={['btn-prev', { disabled: this.$parent.internalCurrentPage <= 1 }]}
on-click={ this.$parent.prev }> on-click={ this.$parent.prev }>
<i class="el-icon el-icon-arrow-left"></i> <i class="el-icon el-icon-arrow-left"></i>
@ -112,6 +113,7 @@ export default {
render(h) { render(h) {
return ( return (
<button <button
type="button"
class={[ class={[
'btn-next', 'btn-next',
{ disabled: this.$parent.internalCurrentPage === this.$parent.internalPageCount || this.$parent.internalPageCount === 0 } { disabled: this.$parent.internalCurrentPage === this.$parent.internalPageCount || this.$parent.internalPageCount === 0 }

View File

@ -1,12 +1,13 @@
<template> <template>
<label class="el-radio"> <label class="el-radio">
<span class="el-radio__input"> <span class="el-radio__input"
<span class="el-radio__inner" :class="{
:class="{
'is-disabled': disabled, 'is-disabled': disabled,
'is-checked': model === label, 'is-checked': model === label,
'is-focus': focus 'is-focus': focus
}"></span> }"
>
<span class="el-radio__inner"></span>
<input <input
class="el-radio__original" class="el-radio__original"
:value="label" :value="label"

View File

@ -92,11 +92,6 @@
}, },
value() { value() {
this.dispatch('ElSelect', 'setSelected'); this.dispatch('ElSelect', 'setSelected');
},
visible() {
this.$nextTick(() => {
this.dispatch('ElSelectDropdown', 'updatePopper');
});
} }
}, },

View File

@ -233,7 +233,9 @@
}, },
query(val) { query(val) {
this.broadcast('ElSelectDropdown', 'updatePopper'); this.$nextTick(() => {
this.broadcast('ElSelectDropdown', 'updatePopper');
});
this.hoverIndex = -1; this.hoverIndex = -1;
if (this.multiple && this.filterable) { if (this.multiple && this.filterable) {
this.resetInputHeight(); this.resetInputHeight();
@ -557,7 +559,7 @@
deleteTag(event, tag) { deleteTag(event, tag) {
let index = this.selected.indexOf(tag); let index = this.selected.indexOf(tag);
if (index > -1) { if (index > -1 && !this.disabled) {
this.value.splice(index, 1); this.value.splice(index, 1);
} }
event.stopPropagation(); event.stopPropagation();

View File

@ -38,7 +38,7 @@ export default {
<tbody> <tbody>
{ {
this._l(this.data, (row, $index) => this._l(this.data, (row, $index) =>
<tr [<tr
style={ this.rowStyle ? this.getRowStyle(row, $index) : null } style={ this.rowStyle ? this.getRowStyle(row, $index) : null }
key={ this.table.rowKey ? this.getKeyOfRow(row, $index) : $index } key={ this.table.rowKey ? this.getKeyOfRow(row, $index) : $index }
on-dblclick={ ($event) => this.handleDoubleClick($event, row) } on-dblclick={ ($event) => this.handleDoubleClick($event, row) }
@ -46,7 +46,7 @@ export default {
on-contextmenu={ ($event) => this.handleContextMenu($event, row) } on-contextmenu={ ($event) => this.handleContextMenu($event, row) }
on-mouseenter={ _ => this.handleMouseEnter($index) } on-mouseenter={ _ => this.handleMouseEnter($index) }
on-mouseleave={ _ => this.handleMouseLeave() } on-mouseleave={ _ => this.handleMouseLeave() }
class={ this.getRowClass(row, $index) }> class={ [this.getRowClass(row, $index)] }>
{ {
this._l(this.columns, (column, cellIndex) => this._l(this.columns, (column, cellIndex) =>
<td <td
@ -62,7 +62,15 @@ export default {
{ {
!this.fixed && this.layout.scrollY && this.layout.gutterWidth ? <td class="gutter" /> : '' !this.fixed && this.layout.scrollY && this.layout.gutterWidth ? <td class="gutter" /> : ''
} }
</tr> </tr>,
this.store.states.expandRows.indexOf(row) > -1
? (<tr>
<td colspan={ this.columns.length } class="el-table__expanded-cell">
{ this.$parent.renderExpanded ? this.$parent.renderExpanded.call(this._renderProxy, h, { row, $index, store: this.store, _self: this.$parent.$vnode.context }) : ''}
</td>
</tr>)
: ''
]
) )
} }
</tbody> </tbody>
@ -95,6 +103,8 @@ export default {
const newRow = rows[data.indexOf(newVal)]; const newRow = rows[data.indexOf(newVal)];
if (oldRow) { if (oldRow) {
oldRow.classList.remove('current-row'); oldRow.classList.remove('current-row');
} else if (rows) {
[].forEach.call(rows, row => row.classList.remove('current-row'));
} }
if (newRow) { if (newRow) {
newRow.classList.add('current-row'); newRow.classList.add('current-row');
@ -180,7 +190,7 @@ export default {
if (cell) { if (cell) {
const column = getColumnByCell(table, cell); const column = getColumnByCell(table, cell);
const hoverState = table.hoverState = { cell, column, row }; const hoverState = table.hoverState = {cell, column, row};
table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event); table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event);
} }
@ -230,6 +240,10 @@ export default {
this.store.commit('setCurrentRow', row); this.store.commit('setCurrentRow', row);
table.$emit('row-click', row, event, column); table.$emit('row-click', row, event, column);
},
handleExpandClick(row) {
this.store.commit('toggleRowExpanded', row);
} }
} }
}; };

View File

@ -16,6 +16,12 @@ const defaults = {
order: '', order: '',
className: 'el-table-column--selection' className: 'el-table-column--selection'
}, },
expand: {
width: 48,
minWidth: 48,
realWidth: 48,
order: ''
},
index: { index: {
width: 48, width: 48,
minWidth: 48, minWidth: 48,
@ -48,6 +54,21 @@ const forced = {
return <div>{ $index + 1 }</div>; return <div>{ $index + 1 }</div>;
}, },
sortable: false sortable: false
},
expand: {
renderHeader: function(h, {}) {
return '';
},
renderCell: function(h, { row, store }, proxy) {
const expanded = store.states.expandRows.indexOf(row) > -1;
return <div class={ 'el-table__expand-icon ' + (expanded ? 'el-table__expand-icon--expanded' : '') }
on-click={ () => proxy.handleExpandClick(row) }>
<i class='el-icon el-icon-arrow-right'></i>
</div>;
},
sortable: false,
resizable: false,
className: 'el-table__expand-column'
} }
}; };
@ -114,6 +135,7 @@ export default {
context: {}, context: {},
columnKey: String, columnKey: String,
align: String, align: String,
headerAlign: String,
showTooltipWhenOverflow: Boolean, showTooltipWhenOverflow: Boolean,
showOverflowTooltip: Boolean, showOverflowTooltip: Boolean,
fixed: [Boolean, String], fixed: [Boolean, String],
@ -199,6 +221,7 @@ export default {
isColumnGroup, isColumnGroup,
context: this.context, context: this.context,
align: this.align ? 'is-' + this.align : null, align: this.align ? 'is-' + this.align : null,
headerAlign: this.headerAlign ? 'is-' + this.headerAlign : (this.align ? 'is-' + this.align : null),
sortable: this.sortable, sortable: this.sortable,
sortMethod: this.sortMethod, sortMethod: this.sortMethod,
resizable: this.resizable, resizable: this.resizable,
@ -217,9 +240,35 @@ export default {
objectAssign(column, forced[type] || {}); objectAssign(column, forced[type] || {});
this.columnConfig = column;
let renderCell = column.renderCell; let renderCell = column.renderCell;
let _self = this; let _self = this;
if (type === 'expand') {
owner.renderExpanded = function(h, data) {
if (_self.$vnode.data.inlineTemplate) {
data._self = _self.context || data._self;
if (Object.prototype.toString.call(data._self) === '[object Object]') {
for (let prop in data._self) {
if (!data.hasOwnProperty(prop)) {
data[prop] = data._self[prop];
}
}
}
data._staticTrees = _self._staticTrees;
data.$options.staticRenderFns = _self.$options.staticRenderFns;
return _self.customRender.call(data);
}
};
column.renderCell = function(h, data) {
return <div class="cell">{ renderCell(h, data, this._renderProxy) }</div>;
};
return;
}
column.renderCell = function(h, data) { column.renderCell = function(h, data) {
if (_self.$vnode.data.inlineTemplate) { if (_self.$vnode.data.inlineTemplate) {
renderCell = function() { renderCell = function() {
@ -254,8 +303,6 @@ export default {
</el-tooltip> </el-tooltip>
: <div class="cell">{ renderCell(h, data) }</div>; : <div class="cell">{ renderCell(h, data) }</div>;
}; };
this.columnConfig = column;
}, },
destroyed() { destroyed() {
@ -300,6 +347,12 @@ export default {
} }
}, },
headerAlign(newVal) {
if (this.columnConfig) {
this.columnConfig.headerAlign = newVal ? 'is-' + newVal : this.align;
}
},
width(newVal) { width(newVal) {
if (this.columnConfig) { if (this.columnConfig) {
this.columnConfig.width = newVal; this.columnConfig.width = newVal;

View File

@ -103,7 +103,7 @@ export default {
on-mouseout={ this.handleMouseOut } on-mouseout={ this.handleMouseOut }
on-mousedown={ ($event) => this.handleMouseDown($event, column) } on-mousedown={ ($event) => this.handleMouseDown($event, column) }
on-click={ ($event) => this.handleClick($event, column) } on-click={ ($event) => this.handleClick($event, column) }
class={ [column.id, column.order, column.align, column.className || '', rowIndex === 0 && this.isCellHidden(cellIndex) ? 'is-hidden' : '', !column.children ? 'is-leaf' : ''] }> class={ [column.id, column.order, column.headerAlign, column.className || '', rowIndex === 0 && this.isCellHidden(cellIndex) ? 'is-hidden' : '', !column.children ? 'is-leaf' : ''] }>
<div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : ''] }> <div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : ''] }>
{ {
column.renderHeader column.renderHeader
@ -112,9 +112,9 @@ export default {
} }
{ {
column.sortable column.sortable
? <span class="caret-wrapper" on-click={ ($event) => this.handleHeaderClick($event, column) }> ? <span class="caret-wrapper">
<i class="sort-caret ascending"></i> <i class="sort-caret ascending" on-click={ ($event) => this.handleHeaderClick($event, column, 'ascending')}></i>
<i class="sort-caret descending"></i> <i class="sort-caret descending" on-click={ ($event) => this.handleHeaderClick($event, column, 'descending')}></i>
</span> </span>
: '' : ''
} }
@ -334,7 +334,7 @@ export default {
document.body.style.cursor = ''; document.body.style.cursor = '';
}, },
handleHeaderClick(event, column) { handleHeaderClick(event, column, order) {
let target = event.target; let target = event.target;
while (target && target.tagName !== 'TH') { while (target && target.tagName !== 'TH') {
target = target.parentNode; target = target.parentNode;
@ -362,15 +362,14 @@ export default {
sortProp = column.property; sortProp = column.property;
} }
if (!column.order) { if (column.order === order) {
sortOrder = column.order = 'ascending';
} else if (column.order === 'ascending') {
sortOrder = column.order = 'descending';
} else {
sortOrder = column.order = null; sortOrder = column.order = null;
states.sortingColumn = null; states.sortingColumn = null;
sortProp = null; sortProp = null;
} else {
sortOrder = column.order = order;
} }
states.sortProp = sortProp; states.sortProp = sortProp;
states.sortOrder = sortOrder; states.sortOrder = sortOrder;

View File

@ -69,7 +69,9 @@ const TableStore = function(table, initialState = {}) {
selectable: null, selectable: null,
currentRow: null, currentRow: null,
hoverRow: null, hoverRow: null,
filters: {} filters: {},
expandRows: [],
defaultExpandAll: false
}; };
for (let prop in initialState) { for (let prop in initialState) {
@ -85,6 +87,15 @@ TableStore.prototype.mutations = {
states._data = data; states._data = data;
states.data = sortData((data || []), states); states.data = sortData((data || []), states);
states.data.forEach((item) => {
if (!item.$extra) {
Object.defineProperty(item, '$extra', {
value: {},
enumerable: false
});
}
});
this.updateCurrentRow(); this.updateCurrentRow();
if (!states.reserveSelection) { if (!states.reserveSelection) {
@ -114,6 +125,11 @@ TableStore.prototype.mutations = {
} }
} }
const defaultExpandAll = states.defaultExpandAll;
if (defaultExpandAll) {
this.states.expandRows = (states.data || []).slice(0);
}
Vue.nextTick(() => this.table.updateScrollY()); Vue.nextTick(() => this.table.updateScrollY());
}, },
@ -218,6 +234,26 @@ TableStore.prototype.mutations = {
this.updateAllSelected(); this.updateAllSelected();
}, },
toggleRowExpanded: function(states, row, expanded) {
const expandRows = states.expandRows;
if (typeof expanded !== 'undefined') {
const index = expandRows.indexOf(row);
if (expanded) {
if (index === -1) expandRows.push(row);
} else {
if (index !== -1) expandRows.splice(index, 1);
}
} else {
const index = expandRows.indexOf(row);
if (index === -1) {
expandRows.push(row);
} else {
expandRows.splice(index, 1);
}
}
this.table.$emit('expand', row, expandRows.indexOf(row) !== -1);
},
toggleAllSelection: debounce(10, function(states) { toggleAllSelection: debounce(10, function(states) {
const data = states.data || []; const data = states.data || [];
const value = !states.isAllSelected; const value = !states.isAllSelected;
@ -286,6 +322,22 @@ TableStore.prototype.clearSelection = function() {
} }
}; };
TableStore.prototype.setExpandRowKeys = function(rowKeys) {
const expandRows = [];
const data = this.states.data;
const rowKey = this.states.rowKey;
if (!rowKey) throw new Error('[Table] prop row-key should not be empty.');
const keysMap = getKeysMap(data, rowKey);
rowKeys.forEach((key) => {
const info = keysMap[key];
if (info) {
expandRows.push(info.row);
}
});
this.states.expandRows = expandRows;
};
TableStore.prototype.toggleRowSelection = function(row, selected) { TableStore.prototype.toggleRowSelection = function(row, selected) {
const changed = toggleRowSelection(this.states, row, selected); const changed = toggleRowSelection(this.states, row, selected);
if (changed) { if (changed) {
@ -395,6 +447,8 @@ TableStore.prototype.commit = function(name, ...args) {
const mutations = this.mutations; const mutations = this.mutations;
if (mutations[name]) { if (mutations[name]) {
mutations[name].apply(this, [this.states].concat(args)); mutations[name].apply(this, [this.states].concat(args));
} else {
throw new Error(`Action not found: ${name}`);
} }
}; };

View File

@ -164,7 +164,11 @@
highlightCurrentRow: Boolean, highlightCurrentRow: Boolean,
emptyText: String emptyText: String,
expandRowKeys: Array,
defaultExpandAll: Boolean
}, },
components: { components: {
@ -356,6 +360,10 @@
handler(val) { handler(val) {
this.store.commit('setData', val); this.store.commit('setData', val);
} }
},
expandRowKeys(newVal) {
this.store.setExpandRowKeys(newVal);
} }
}, },
@ -372,7 +380,8 @@
data() { data() {
const store = new TableStore(this, { const store = new TableStore(this, {
rowKey: this.rowKey rowKey: this.rowKey,
defaultExpandAll: this.defaultExpandAll
}); });
const layout = new TableLayout({ const layout = new TableLayout({
store, store,
@ -383,6 +392,7 @@
return { return {
store, store,
layout, layout,
renderExpanded: null,
resizeProxyVisible: false resizeProxyVisible: false
}; };
} }

View File

@ -1,3 +1,10 @@
<template>
<div class="el-tab-pane">
<div class="el-tab-pane__content" v-show="active">
<slot></slot>
</div>
</div>
</template>
<script> <script>
module.exports = { module.exports = {
name: 'el-tab-pane', name: 'el-tab-pane',
@ -12,73 +19,33 @@
data() { data() {
return { return {
counter: 0, index: null
transition: '',
paneStyle: {
position: 'relative'
},
isClosable: null,
index: ''
}; };
}, },
created() { computed: {
const propsData = this.$options.propsData; isClosable() {
if (propsData && typeof propsData.closable !== 'undefined') { return this.closable || this.$parent.closable;
this.isClosable = propsData.closable === '' || propsData.closable; },
} else { active() {
this.isClosable = this.$parent.closable; return this.$parent.currentName === (this.name || this.index);
}
if (!this.index) {
this.index = this.$parent.$children.indexOf(this) + 1 + '';
}
if (this.$parent.panes) {
this.$parent.panes.push(this);
} }
}, },
computed: { created() {
show() { this.$parent.$forceUpdate();
return this.$parent.currentName === this.index;
}
}, },
destroyed() { destroyed() {
if (this.$el && this.$el.parentNode) { if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el); this.$el.parentNode.removeChild(this.$el);
} }
const panes = this.$parent.panes;
if (panes) {
panes.splice(this, panes.indexOf(this));
}
}, },
watch: { watch: {
name: {
immediate: true,
handler(val) {
this.index = val;
}
},
closable(val) {
this.isClosable = val;
},
'$parent.currentName'(newValue, oldValue) {
if (this.index === newValue) {
this.transition = newValue > oldValue ? 'slideInRight' : 'slideInLeft';
}
if (this.index === oldValue) {
this.transition = oldValue > newValue ? 'slideInRight' : 'slideInLeft';
}
},
label() { label() {
this.$parent.$forceUpdate(); this.$parent.$forceUpdate();
} }
} }
}; };
</script> </script>
<template>
<div class="el-tab-pane" v-show="show && $slots.default">
<slot></slot>
</div>
</template>

View File

@ -4,69 +4,84 @@
props: { props: {
type: String, type: String,
tabPosition: String,
activeName: String, activeName: String,
closable: false, closable: {
tabWidth: 0 type: Boolean,
default: false
},
value: {}
}, },
data() { data() {
return { return {
children: null, children: null,
activeTab: null, currentName: this.value || this.activeName
currentName: 0,
panes: []
}; };
}, },
watch: { watch: {
activeName: { activeName(val) {
handler(val) { this.currentName = val;
this.currentName = val; },
} value(val) {
this.currentName = val;
},
currentName(val) {
this.$emit('input', val);
} }
}, },
methods: { methods: {
handleTabRemove(tab, event) { handleTabRemove(tab, event) {
event.stopPropagation(); event.stopPropagation();
let tabs = this.$children; const tabs = this.$children;
var index = tabs.indexOf(tab); let index = tabs.indexOf(tab);
tab.$destroy(true); tab.$destroy();
if (tab.index === this.currentName) {
let nextChild = tabs[index];
let prevChild = tabs[index - 1];
while (prevChild && prevChild.disabled) {
prevChild = tabs[tabs.indexOf(prevChild) - 1];
}
this.currentName = nextChild
? nextChild.index
: prevChild
? prevChild.index
: '-1';
}
this.$emit('tab-remove', tab); this.$emit('tab-remove', tab);
this.$forceUpdate(); this.$forceUpdate();
},
handleTabClick(tab, event) {
if (tab.disabled) return;
this.currentName = tab.index;
this.$emit('tab-click', tab, event);
},
calcBarStyle() {
if (this.type || !this.$refs.tabs) return {};
var style = {};
var offset = 0;
var tabWidth = 0;
this.$children.every((panel, index) => { this.$nextTick(_ => {
if (tab.active) {
let nextChild = tabs[index];
let prevChild = tabs[index - 1];
let nextActiveTab = nextChild || prevChild || null;
if (nextActiveTab) {
this.currentName = nextActiveTab.name || nextActiveTab.index;
}
}
});
},
handleTabClick(tab, tabName, event) {
if (tab.disabled) return;
this.currentName = tabName;
this.$emit('tab-click', tab, event);
}
},
mounted() {
this.$forceUpdate();
},
render(h) {
let {
type,
handleTabRemove,
handleTabClick,
currentName
} = this;
const getBarStyle = () => {
if (this.type || !this.$refs.tabs) return {};
let style = {};
let offset = 0;
let tabWidth = 0;
this.$children.every((tab, index) => {
let $el = this.$refs.tabs[index]; let $el = this.$refs.tabs[index];
if (!$el) { return false; } if (!$el) { return false; }
if (panel.index !== this.currentName) {
if (!tab.active) {
offset += $el.clientWidth; offset += $el.clientWidth;
return true; return true;
} else { } else {
@ -79,51 +94,45 @@
style.transform = `translateX(${offset}px)`; style.transform = `translateX(${offset}px)`;
return style; return style;
} };
},
mounted() {
this.currentName = this.activeName || this.$children[0] && this.$children[0].index || '1';
this.$nextTick(() => {
this.$forceUpdate();
});
},
render(h) {
let {
type,
panes, // eslint-disable-line
handleTabRemove,
handleTabClick,
currentName
} = this;
const barStyle = this.calcBarStyle();
const activeBar = !type
? <div class="el-tabs__active-bar" style={barStyle}></div>
: null;
const tabs = this.$children.map((tab, index) => { const tabs = this.$children.map((tab, index) => {
let btnClose = h('span', { let tabName = tab.name || tab.index || index;
class: { if (currentName === undefined && index === 0) {
'el-icon-close': true this.currentName = tabName;
}, }
on: { click: (ev) => { handleTabRemove(tab, ev); } }
}); tab.index = index;
const _tab = h('div', {
class: { const activeBar = !type && index === 0
'el-tabs__item': true, ? <div class="el-tabs__active-bar" style={getBarStyle()}></div>
'is-active': currentName === tab.index, : null;
'is-disabled': tab.disabled,
'is-closable': tab.isClosable const btnClose = tab.isClosable
}, ? <span class="el-icon-close" on-click={(ev) => { handleTabRemove(tab, ev); }}></span>
ref: 'tabs', : null;
refInFor: true,
on: { click: (ev) => { handleTabClick(tab, ev); } } const tabLabelContent = tab.labelContent
}, [ ? tab.labelContent.call(this._renderProxy, h, tab)
tab.labelContent ? tab.labelContent.call(this._renderProxy, h, tab) : tab.label, : tab.label;
tab.isClosable ? btnClose : null,
index === 0 ? activeBar : null return (
]); <div
return _tab; class={{
'el-tabs__item': true,
'is-active': tab.active,
'is-disabled': tab.disabled,
'is-closable': tab.isClosable
}}
ref="tabs"
refInFor
on-click={(ev) => { handleTabClick(tab, tabName, ev); }}
>
{tabLabelContent}
{btnClose}
{activeBar}
</div>
);
}); });
return ( return (
<div class={{ <div class={{

View File

@ -1,6 +1,6 @@
{ {
"name": "element-theme-default", "name": "element-theme-default",
"version": "1.0.8", "version": "1.0.9",
"description": "Element component default theme.", "description": "Element component default theme.",
"main": "lib/index.css", "main": "lib/index.css",
"style": "lib/index.css", "style": "lib/index.css",

View File

@ -19,6 +19,83 @@
line-height: 1; line-height: 1;
position: relative; position: relative;
vertical-align: middle; vertical-align: middle;
@when disabled {
.el-checkbox__inner {
background-color: var(--checkbox-disabled-input-fill);
border-color: var(--checkbox-disabled-input-border-color);
cursor: not-allowed;
&::after {
cursor: not-allowed;
border-color: var(--checkbox-disabled-icon-color);
}
& + .el-checkbox__label {
cursor: not-allowed;
}
}
&.is-checked {
.el-checkbox__inner {
background-color: var(--checkbox-disabled-checked-input-fill);
border-color: var(--checkbox-disabled-checked-input-border-color);
&::after {
border-color: var(--checkbox-disabled-checked-icon-color);
}
}
}
&.is-indeterminate {
.el-checkbox__inner {
background-color: var(--checkbox-disabled-checked-input-fill);
border-color: var(--checkbox-disabled-checked-input-border-color);
&::before {
border-color: var(--checkbox-disabled-checked-icon-color);
}
}
}
& + .el-checkbox__label {
color: var(--disabled-color-base);
cursor: not-allowed;
}
}
@when checked {
.el-checkbox__inner {
background-color: var(--checkbox-checked-input-fill);
border-color: var(--checkbox-checked-input-border-color);
&::after {
transform: rotate(45deg) scaleY(1);
}
}
}
@when focus {
.el-checkbox__inner {
border-color: var(--checkbox-input-border-color-hover);
}
}
@when indeterminate {
.el-checkbox__inner {
background-color: var(--checkbox-checked-input-fill);
border-color: var(--checkbox-checked-input-border-color);
&::before {
content: '';
position: absolute;
display: block;
border: 1px solid var(--checkbox-checked-icon-color);
margin-top: -1px;
left: 3px;
right: 3px;
top: 50%;
}
&::after {
display: none;
}
}
}
} }
@e inner { @e inner {
display: inline-block; display: inline-block;
@ -31,7 +108,7 @@
transition: border-color .25s cubic-bezier(.71,-.46,.29,1.46), transition: border-color .25s cubic-bezier(.71,-.46,.29,1.46),
background-color .25s cubic-bezier(.71,-.46,.29,1.46); background-color .25s cubic-bezier(.71,-.46,.29,1.46);
&:not(.is-disabled):hover { &:hover {
border-color: var(--checkbox-input-border-color-hover); border-color: var(--checkbox-input-border-color-hover);
} }
@ -50,72 +127,6 @@
transition: transform .15s cubic-bezier(.71,-.46,.88,.6) .05s; transition: transform .15s cubic-bezier(.71,-.46,.88,.6) .05s;
transform-origin: center; transform-origin: center;
} }
@when disabled {
background-color: var(--checkbox-disabled-input-fill);
border-color: var(--checkbox-disabled-input-border-color);
cursor: not-allowed;
&::after {
cursor: not-allowed;
border-color: var(--checkbox-disabled-icon-color);
}
& + .el-checkbox__label {
cursor: not-allowed;
}
}
@when checked {
background-color: var(--checkbox-checked-input-fill);
border-color: var(--checkbox-checked-input-border-color);
&::after {
transform: rotate(45deg) scaleY(1);
}
}
@when focus {
border-color: var(--checkbox-input-border-color-hover);
}
&.is-disabled.is-checked {
background-color: var(--checkbox-disabled-checked-input-fill);
border-color: var(--checkbox-disabled-checked-input-border-color);
&::after {
border-color: var(--checkbox-disabled-checked-icon-color);
}
}
@when indeterminate {
background-color: var(--checkbox-checked-input-fill);
border-color: var(--checkbox-checked-input-border-color);
&::before {
content: '';
position: absolute;
display: block;
border: 1px solid var(--checkbox-checked-icon-color);
margin-top: -1px;
left: 3px;
right: 3px;
top: 50%;
}
&::after {
display: none;
}
}
&.is-disabled.is-indeterminate {
background-color: var(--checkbox-disabled-checked-input-fill);
border-color: var(--checkbox-disabled-checked-input-border-color);
&::before {
border-color: var(--checkbox-disabled-checked-icon-color);
}
}
} }
@e original { @e original {

View File

@ -7,26 +7,41 @@
} }
@for $i from 1 to 24 { @for $i from 1 to 24 {
.el-col-$i, .el-col-$i {
.el-col-xs-$i {
width: calc(1 / 24 * $(i) * 100)%; width: calc(1 / 24 * $(i) * 100)%;
} }
.el-col-offset-$i, .el-col-offset-$i {
.el-col-xs-offset-$i {
margin-left: calc(1 / 24 * $(i) * 100)%; margin-left: calc(1 / 24 * $(i) * 100)%;
} }
.el-col-pull-$i, .el-col-pull-$i {
.el-col-xs-pull-$i {
position: relative; position: relative;
right: calc(1 / 24 * $(i) * 100)%; right: calc(1 / 24 * $(i) * 100)%;
} }
.el-col-push-$i, .el-col-push-$i {
.el-col-xs-push-$i {
position: relative; position: relative;
left: calc(1 / 24 * $(i) * 100)%; left: calc(1 / 24 * $(i) * 100)%;
} }
} }
@media (max-width: 768px) {
@for $i from 1 to 24 {
.el-col-xs-$i {
width: calc(1 / 24 * $(i) * 100)%;
}
.el-col-xs-offset-$i {
margin-left: calc(1 / 24 * $(i) * 100)%;
}
.el-col-xs-pull-$i {
position: relative;
right: calc(1 / 24 * $(i) * 100)%;
}
.el-col-xs-push-$i {
position: relative;
left: calc(1 / 24 * $(i) * 100)%;
}
}
}
@media (min-width: 768px) { @media (min-width: 768px) {
@for $i from 1 to 24 { @for $i from 1 to 24 {
.el-col-sm-$i { .el-col-sm-$i {

View File

@ -23,9 +23,14 @@
color: #99A9BF; color: #99A9BF;
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
z-index: 1;
&:hover { &:hover {
color: var(--color-primary); color: var(--color-primary);
&:not(.is-disabled) ~ .el-input .el-input__inner:not(.is-disabled) {
border-color: var(--input-focus-border);
}
} }
@when disabled { @when disabled {

View File

@ -7,6 +7,7 @@
white-space: nowrap; white-space: nowrap;
padding: 2px 5px; padding: 2px 5px;
color: var(--pagination-color); color: var(--pagination-color);
@utils-clearfix;
span, span,
button { button {

View File

@ -24,6 +24,54 @@
line-height: 1; line-height: 1;
position: relative; position: relative;
vertical-align: middle; vertical-align: middle;
@when disabled {
.el-radio__inner {
background-color: var(--radio-disabled-input-fill);
border-color: var(--radio-disabled-input-border-color);
cursor: not-allowed;
&::after {
cursor: not-allowed;
background-color: var(--radio-disabled-icon-color);
}
& + .el-radio__label {
cursor: not-allowed;
}
}
&.is-checked {
.el-radio__inner {
background-color: var(--radio-disabled-checked-input-fill);
border-color: var(--radio-disabled-checked-input-border-color);
&::after {
background-color: var(--radio-disabled-checked-icon-color);
}
}
}
& + .el-radio__label {
color: var(--disabled-color-base);
cursor: not-allowed;
}
}
@when checked {
.el-radio__inner {
border-color: var(--radio-checked-input-border-color);
background: var(--radio-checked-icon-color);
&::after {
transform: translate(-50%, -50%) scale(1);
}
}
}
@when focus {
.el-radio__inner {
border-color: var(--radio-input-border-color-hover);
}
}
} }
@e inner { @e inner {
border: var(--radio-input-border); border: var(--radio-input-border);
@ -34,7 +82,7 @@
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
&:not(.is-disabled):hover { &:hover {
border-color: var(--radio-input-border-color-hover); border-color: var(--radio-input-border-color-hover);
} }
@ -47,43 +95,6 @@
transform: translate(-50%, -50%) scale(0); transform: translate(-50%, -50%) scale(0);
transition: transform .15s cubic-bezier(.71,-.46,.88,.6); transition: transform .15s cubic-bezier(.71,-.46,.88,.6);
} }
@when disabled {
background-color: var(--radio-disabled-input-fill);
border-color: var(--radio-disabled-input-border-color);
cursor: not-allowed;
&::after {
cursor: not-allowed;
background-color: var(--radio-disabled-icon-color);
}
& + .el-radio__label {
cursor: not-allowed;
}
}
@when checked {
border-color: var(--radio-checked-input-border-color);
background: var(--radio-checked-icon-color);
&::after {
transform: translate(-50%, -50%) scale(1);
}
}
@when focus {
border-color: var(--radio-input-border-color-hover);
}
&.is-disabled.is-checked {
background-color: var(--radio-disabled-checked-input-fill);
border-color: var(--radio-disabled-checked-input-border-color);
&::after {
background-color: var(--radio-disabled-checked-icon-color);
}
}
} }
@e original { @e original {

View File

@ -66,6 +66,44 @@
color: #5e6d82; color: #5e6d82;
} }
@e expand-column {
.cell {
padding: 0;
text-align: center;
}
}
@e expand-icon {
position: relative;
cursor: pointer;
color: #666;
font-size: 12px;
transition: transform 0.2s ease-in-out;
height: 40px;
@m expanded {
transform: rotate(90deg);
}
> .el-icon {
position: absolute;
left: 50%;
top: 50%;
margin-left: -5px;
margin-top: -5px;
}
}
@e expanded-cell {
padding: 20px 50px;
background-color: #f9fafc;
box-shadow: inset 0 2px 0 #f4f4f4;
&:hover {
background-color: #f9fafc !important;
}
}
@modifier fit { @modifier fit {
border-right: 0; border-right: 0;
border-bottom: 0; border-bottom: 0;

View File

@ -147,10 +147,6 @@
} }
} }
} }
@b tab-pane {
width: 100%;
display: inline-block;
}
} }
.slideInRight-transition, .slideInRight-transition,

View File

@ -133,12 +133,12 @@
this.tree.$emit('current-change', store.currentNode ? store.currentNode.data : null, store.currentNode); this.tree.$emit('current-change', store.currentNode ? store.currentNode.data : null, store.currentNode);
this.tree.currentNode = this; this.tree.currentNode = this;
if (this.tree.expandOnClickNode) { if (this.tree.expandOnClickNode) {
this.handleExpandIconClick(event); this.handleExpandIconClick();
} }
this.tree.$emit('node-click', this.node.data, this.node, this); this.tree.$emit('node-click', this.node.data, this.node, this);
}, },
handleExpandIconClick(event) { handleExpandIconClick() {
if (this.expanded) { if (this.expanded) {
this.node.collapse(); this.node.collapse();
} else { } else {

View File

@ -141,7 +141,7 @@ if (typeof window !== 'undefined' && window.Vue) {
}; };
module.exports = { module.exports = {
version: '1.0.8', version: '1.0.9',
locale: locale.use, locale: locale.use,
install, install,
Loading, Loading,

View File

@ -91,6 +91,31 @@ describe('DatePicker', () => {
}, DELAY); }, DELAY);
}); });
it('disabled clear value', done => {
vm = createVue({
template: `
<el-date-picker v-model="value" ref="compo" :clearable="false"></el-date-picker>
`,
data() {
return { value: '' };
}
}, true);
const input = vm.$el.querySelector('input');
input.focus();
setTimeout(_ => {
const $el = vm.$refs.compo.picker.$el;
$el.querySelector('td.available').click();
vm.$nextTick(_ => {
vm.$el.querySelector('.el-input__icon').click();
setTimeout(_ => {
expect(vm.value).to.be.exist;
done();
}, DELAY);
});
}, DELAY);
});
it('reset', done => { it('reset', done => {
vm = createVue({ vm = createVue({
template: ` template: `
@ -120,6 +145,46 @@ describe('DatePicker', () => {
}, DELAY); }, DELAY);
}); });
it('change event', done => {
let inputValue;
vm = createVue({
template: `
<el-date-picker
ref="compo"
v-model="value"
format="yyyy-MM"
@change="handleChange" />`,
methods: {
handleChange(val) {
inputValue = val;
}
},
data() {
return { value: '' };
}
}, true);
const input = vm.$el.querySelector('input');
input.blur();
input.focus();
setTimeout(_ => {
const picker = vm.$refs.compo.picker;
picker.$el.querySelector('td.available').click();
vm.$nextTick(_ => {
const date = picker.date;
expect(inputValue).to.equal(`${date.getFullYear()}-${date.getMonth() + 1 }`);
done();
});
}, DELAY);
});
describe('keydown', () => { describe('keydown', () => {
let input; let input;
let keyDown = function(el, keyCode) { let keyDown = function(el, keyCode) {

View File

@ -38,22 +38,14 @@ describe('InputNumber', () => {
let input = vm.$el.querySelector('input'); let input = vm.$el.querySelector('input');
let btnDecrease = vm.$el.querySelector('.el-input-number__decrease'); let btnDecrease = vm.$el.querySelector('.el-input-number__decrease');
triggerEvent(btnDecrease, 'mouseenter');
triggerEvent(btnDecrease, 'mousedown'); triggerEvent(btnDecrease, 'mousedown');
triggerEvent(document, 'mouseup'); triggerEvent(document, 'mouseup');
setTimeout(_ => { vm.$nextTick(_ => {
expect(vm.$el.querySelector('.el-input.is-active')).to.exist;
expect(vm.value).to.be.equal(4); expect(vm.value).to.be.equal(4);
expect(input.value).to.be.equal('4'); expect(input.value).to.be.equal('4');
done();
triggerEvent(btnDecrease, 'mouseleave'); });
vm.$nextTick(_ => {
expect(vm.$el.querySelector('.el-input.is-active')).to.not.exist;
done();
});
}, 300);
}); });
it('increase', done => { it('increase', done => {
vm = createVue({ vm = createVue({
@ -74,11 +66,11 @@ describe('InputNumber', () => {
triggerEvent(btnIncrease, 'mousedown'); triggerEvent(btnIncrease, 'mousedown');
triggerEvent(document, 'mouseup'); triggerEvent(document, 'mouseup');
setTimeout(_ => { vm.$nextTick(_ => {
expect(vm.value).to.be.equal(2.5); expect(vm.value).to.be.equal(2.5);
expect(input.value).to.be.equal('2.5'); expect(input.value).to.be.equal('2.5');
done(); done();
}, 100); });
}); });
it('disabled', done => { it('disabled', done => {
vm = createVue({ vm = createVue({
@ -100,19 +92,19 @@ describe('InputNumber', () => {
triggerEvent(btnDecrease, 'mousedown'); triggerEvent(btnDecrease, 'mousedown');
triggerEvent(document, 'mouseup'); triggerEvent(document, 'mouseup');
triggerEvent(btnIncrease, 'mousedown'); vm.$nextTick(_ => {
triggerEvent(document, 'mouseup');
setTimeout(_ => {
expect(vm.value).to.be.equal(2); expect(vm.value).to.be.equal(2);
expect(input.value).to.be.equal('2'); expect(input.value).to.be.equal('2');
setTimeout(_ => { triggerEvent(btnIncrease, 'mousedown');
triggerEvent(document, 'mouseup');
vm.$nextTick(_ => {
expect(vm.value).to.be.equal(2); expect(vm.value).to.be.equal(2);
expect(input.value).to.be.equal('2'); expect(input.value).to.be.equal('2');
done(); done();
}, 100); });
}, 100); });
}); });
it('step', done => { it('step', done => {
vm = createVue({ vm = createVue({
@ -134,19 +126,19 @@ describe('InputNumber', () => {
triggerEvent(btnIncrease, 'mousedown'); triggerEvent(btnIncrease, 'mousedown');
triggerEvent(document, 'mouseup'); triggerEvent(document, 'mouseup');
setTimeout(_ => { vm.$nextTick(_ => {
expect(vm.value).to.be.equal(8.2); expect(vm.value).to.be.equal(8.2);
expect(input.value).to.be.equal('8.2'); expect(input.value).to.be.equal('8.2');
triggerEvent(btnDecrease, 'mousedown'); triggerEvent(btnDecrease, 'mousedown');
triggerEvent(document, 'mouseup'); triggerEvent(document, 'mouseup');
setTimeout(_ => { vm.$nextTick(_ => {
expect(vm.value).to.be.equal(5); expect(vm.value).to.be.equal(5);
expect(input.value).to.be.equal('5'); expect(input.value).to.be.equal('5');
done(); done();
}, 100); });
}, 100); });
}); });
it('min', done => { it('min', done => {
vm = createVue({ vm = createVue({
@ -181,11 +173,11 @@ describe('InputNumber', () => {
triggerEvent(btnDecrease, 'mousedown'); triggerEvent(btnDecrease, 'mousedown');
triggerEvent(document, 'mouseup'); triggerEvent(document, 'mouseup');
setTimeout(_ => { vm.$nextTick(_ => {
expect(vm.value).to.be.equal(6); expect(vm.value).to.be.equal(6);
expect(input.value).to.be.equal('6'); expect(input.value).to.be.equal('6');
done(); done();
}, 100); });
}); });
it('max', done => { it('max', done => {
vm = createVue({ vm = createVue({
@ -220,11 +212,11 @@ describe('InputNumber', () => {
triggerEvent(btnIncrease, 'mousedown'); triggerEvent(btnIncrease, 'mousedown');
triggerEvent(document, 'mouseup'); triggerEvent(document, 'mouseup');
setTimeout(_ => { vm.$nextTick(_ => {
expect(vm.value).to.be.equal(8); expect(vm.value).to.be.equal(8);
expect(input.value).to.be.equal('8'); expect(input.value).to.be.equal('8');
done(); done();
}, 100); });
}); });
it('controls', () => { it('controls', () => {
vm = createVue({ vm = createVue({
@ -242,4 +234,30 @@ describe('InputNumber', () => {
expect(vm.$el.querySelector('.el-input-number__decrease')).to.not.exist; expect(vm.$el.querySelector('.el-input-number__decrease')).to.not.exist;
expect(vm.$el.querySelector('.el-input-number__increase')).to.not.exist; expect(vm.$el.querySelector('.el-input-number__increase')).to.not.exist;
}); });
it('event:change', done => {
vm = createVue({
template: `
<el-input-number v-model="value" ref="input">
</el-input-number>
`,
data() {
return {
value: 1.5
};
}
}, true);
let btnIncrease = vm.$el.querySelector('.el-input-number__increase');
const spy = sinon.spy();
vm.$refs.input.$on('change', spy);
triggerEvent(btnIncrease, 'mousedown');
triggerEvent(document, 'mouseup');
vm.$nextTick(_ => {
expect(spy.withArgs(2.5, 1.5).calledOnce).to.be.true;
done();
});
});
}); });

View File

@ -104,6 +104,7 @@ describe('Input', () => {
}, true); }, true);
expect(vm.$el.querySelector('.el-textarea__inner').getAttribute('rows')).to.be.equal('3'); expect(vm.$el.querySelector('.el-textarea__inner').getAttribute('rows')).to.be.equal('3');
}); });
it('autosize', done => { it('autosize', done => {
vm = createVue({ vm = createVue({
template: ` template: `
@ -143,4 +144,57 @@ describe('Input', () => {
done(); done();
}, 200); }, 200);
}); });
describe('Input Events', () => {
it('event:focus & blur', done => {
vm = createVue({
template: `
<el-input
ref="input"
placeholder="请输入内容"
value="input">
</el-input>
`
}, true);
const spyFocus = sinon.spy();
const spyBlur = sinon.spy();
vm.$refs.input.$on('focus', spyFocus);
vm.$refs.input.$on('blur', spyBlur);
vm.$el.querySelector('input').focus();
vm.$el.querySelector('input').blur();
vm.$nextTick(_ => {
expect(spyFocus.calledOnce).to.be.true;
expect(spyBlur.calledOnce).to.be.true;
done();
});
});
it('event:change', done => {
vm = createVue({
template: `
<el-input
ref="input"
placeholder="请输入内容"
:value="input">
</el-input>
`,
data() {
return {
input: 'a'
};
}
}, true);
const spy = sinon.spy();
vm.$refs.input.$on('change', spy);
vm.input = 'b';
vm.$nextTick(_ => {
expect(spy.withArgs('b').calledOnce).to.be.true;
done();
});
});
});
}); });

View File

@ -40,6 +40,18 @@ describe('Pagination', () => {
expect(elm.querySelector('.el-pagination__total')).to.not.exist; expect(elm.querySelector('.el-pagination__total')).to.not.exist;
}); });
it('layout: all in right, need clear float', () => {
vm = createTest(Pagination, {
layout: '->, prev, pager, next',
total: 100
}, true);
const elm = vm.$el;
let right_div = elm.querySelector('.el-pagination__rightwrapper');
expect(elm.clientHeight > 0 && right_div.clientHeight > 0).to.equal(true);
// elm padding , 使 >=
expect(elm.clientHeight >= right_div.clientHeight).to.equal(true);
});
it('custom slot', () => { it('custom slot', () => {
vm = createVue({ vm = createVue({
template: ` template: `

View File

@ -8,11 +8,11 @@ const toArray = function(obj) {
const getTestData = function() { const getTestData = function() {
return [ return [
{ name: 'Toy Story', release: '1995-11-22', director: 'John Lasseter', runtime: 80 }, { id: 1, name: 'Toy Story', release: '1995-11-22', director: 'John Lasseter', runtime: 80 },
{ name: 'A Bug\'s Life', release: '1998-11-25', director: 'John Lasseter', runtime: 95 }, { id: 2, name: 'A Bug\'s Life', release: '1998-11-25', director: 'John Lasseter', runtime: 95 },
{ name: 'Toy Story 2', release: '1999-11-24', director: 'John Lasseter', runtime: 92 }, { id: 3, name: 'Toy Story 2', release: '1999-11-24', director: 'John Lasseter', runtime: 92 },
{ name: 'Monsters, Inc.', release: '2001-11-2', director: 'Peter Docter', runtime: 92 }, { id: 4, name: 'Monsters, Inc.', release: '2001-11-2', director: 'Peter Docter', runtime: 92 },
{ name: 'Finding Nemo', release: '2003-5-30', director: 'Andrew Stanton', runtime: 100 } { id: 5, name: 'Finding Nemo', release: '2003-5-30', director: 'Andrew Stanton', runtime: 100 }
]; ];
}; };
@ -27,6 +27,7 @@ describe('Table', () => {
const vm = createVue({ const vm = createVue({
template: ` template: `
<el-table :data="testData"> <el-table :data="testData">
<el-table-column prop="id" />
<el-table-column prop="name" label="片名" /> <el-table-column prop="name" label="片名" />
<el-table-column prop="release" label="发行日期" /> <el-table-column prop="release" label="发行日期" />
<el-table-column prop="director" label="导演" /> <el-table-column prop="director" label="导演" />
@ -843,12 +844,12 @@ describe('Table', () => {
vm.$el.querySelectorAll('.el-checkbox')[1].click(); vm.$el.querySelectorAll('.el-checkbox')[1].click();
setTimeout(_ => { setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-checkbox__inner.is-checked')).to.length(1); expect(vm.$el.querySelectorAll('.el-checkbox__input.is-checked')).to.length(1);
// go to second page // go to second page
vm.testData = getData(1); vm.testData = getData(1);
setTimeout(_ => { setTimeout(_ => {
// expect no checked // expect no checked
expect(vm.$el.querySelectorAll('.el-checkbox__inner.is-checked')).to.length(0); expect(vm.$el.querySelectorAll('.el-checkbox__input.is-checked')).to.length(0);
// click first checkbox // click first checkbox
vm.$el.querySelectorAll('.el-checkbox')[1].click(); vm.$el.querySelectorAll('.el-checkbox')[1].click();
vm.$el.querySelectorAll('.el-checkbox')[2].click(); vm.$el.querySelectorAll('.el-checkbox')[2].click();
@ -856,11 +857,11 @@ describe('Table', () => {
// back first page // back first page
vm.testData = getData(); vm.testData = getData();
setTimeout(_ => { setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-checkbox__inner.is-checked')).to.length(1); expect(vm.$el.querySelectorAll('.el-checkbox__input.is-checked')).to.length(1);
// clear // clear
vm.$refs.table.clearSelection(); vm.$refs.table.clearSelection();
setTimeout(_ => { setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-checkbox__inner.is-checked')).to.length(0); expect(vm.$el.querySelectorAll('.el-checkbox__input.is-checked')).to.length(0);
destroyVM(vm); destroyVM(vm);
done(); done();
}, DELAY); }, DELAY);
@ -957,6 +958,90 @@ describe('Table', () => {
}, DELAY); }, DELAY);
}); });
}); });
describe('= expand', () => {
const createInstance = function(extra) {
extra = extra || '';
return createVue({
template: `
<el-table row-key="id" :data="testData" @expand="handleExpand" ${extra}>
<el-table-column type="expand" inline-template>
<div>{{row.name}}</div>
</el-table-column>
<el-table-column prop="release" label="release" />
<el-table-column prop="director" label="director" />
<el-table-column prop="runtime" label="runtime" />
</el-table>
`,
created() {
this.testData = getTestData();
},
data() {
return { expandCount: 0, expandRowKeys: [] };
},
methods: {
handleExpand() {
this.expandCount++;
}
}
}, true);
};
it('works', done => {
const vm = createInstance();
setTimeout(_ => {
expect(vm.$el.querySelectorAll('td.el-table__expand-column').length).to.equal(5);
destroyVM(vm);
done();
}, DELAY);
});
it('should expand when click icon', done => {
const vm = createInstance();
setTimeout(_ => {
vm.$el.querySelector('td.el-table__expand-column .el-table__expand-icon').click();
setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-table__expanded-cell').length).to.equal(1);
expect(vm.expandCount).to.equal(1);
vm.$el.querySelector('td.el-table__expand-column .el-table__expand-icon').click();
setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-table__expanded-cell').length).to.equal(0);
expect(vm.expandCount).to.equal(2);
destroyVM(vm);
done();
}, DELAY);
}, DELAY);
}, DELAY);
});
it('should set expanded rows using expandRowKeys', done => {
const vm = createInstance(':expand-row-keys="expandRowKeys"');
setTimeout(_ => {
vm.expandRowKeys = [1, 3];
setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-table__expanded-cell').length).to.equal(2);
vm.expandRowKeys = [2];
setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-table__expanded-cell').length).to.equal(1);
destroyVM(vm);
done();
}, DELAY);
}, DELAY);
}, DELAY);
});
it('should default-expand-all when default-expand-all is true', done => {
const vm = createInstance('default-expand-all');
setTimeout(_ => {
expect(vm.$el.querySelectorAll('.el-table__expanded-cell').length).to.equal(5);
destroyVM(vm);
done();
}, DELAY);
});
});
}); });
describe('sortable', () => { describe('sortable', () => {
@ -981,7 +1066,7 @@ describe('Table', () => {
}); });
setTimeout(_ => { setTimeout(_ => {
const elm = vm.$el.querySelector('.caret-wrapper'); const elm = vm.$el.querySelector('.caret-wrapper > .ascending');
elm.click(); elm.click();
setTimeout(_ => { setTimeout(_ => {
@ -1003,7 +1088,7 @@ describe('Table', () => {
} }
}, '@sort-change="sortChange"'); }, '@sort-change="sortChange"');
setTimeout(_ => { setTimeout(_ => {
const elm = vm.$el.querySelector('.caret-wrapper'); const elm = vm.$el.querySelector('.caret-wrapper > .ascending');
elm.click(); elm.click();
setTimeout(_ => { setTimeout(_ => {
@ -1019,7 +1104,7 @@ describe('Table', () => {
const vm = createTable('', '', '', 'sortable'); const vm = createTable('', '', '', 'sortable');
it('ascending', done => { it('ascending', done => {
const elm = vm.$el.querySelector('.caret-wrapper'); const elm = vm.$el.querySelector('.caret-wrapper > .ascending');
elm.click(); elm.click();
setTimeout(_ => { setTimeout(_ => {
@ -1031,7 +1116,7 @@ describe('Table', () => {
}); });
it('descending', done => { it('descending', done => {
const elm = vm.$el.querySelector('.caret-wrapper'); const elm = vm.$el.querySelector('.caret-wrapper > .descending');
elm.click(); elm.click();
setTimeout(_ => { setTimeout(_ => {
@ -1215,6 +1300,43 @@ describe('Table', () => {
}, DELAY); }, DELAY);
}); });
it('header-align', (done) => {
const vm = createVue({
template: `
<el-table :data="testData">
<el-table-column prop="name" :align="align" :header-align="headerAlign"/>
</el-table>
`,
data() {
return {
align: 'left',
headerAlign: null
};
},
created() {
this.testData = getTestData();
}
}, true);
setTimeout(() => {
expect(vm.$el.querySelectorAll('.el-table__header th.is-left').length > 0).to.be.true;
expect(vm.$el.querySelectorAll('.el-table__header td.is-center').length === 0).to.be.true;
vm.align = 'right';
vm.$nextTick(() => {
expect(vm.$el.querySelectorAll('.el-table__header th.is-right').length > 0).to.be.true;
expect(vm.$el.querySelectorAll('.el-table__header td.is-center').length === 0).to.be.true;
vm.headerAlign = 'center';
vm.$nextTick(() => {
expect(vm.$el.querySelectorAll('.el-table__header th.is-right').length === 0).to.be.true;
expect(vm.$el.querySelectorAll('.el-table__header td.is-center').length > 0).to.be.true;
});
});
done();
}, DELAY);
});
it('width', (done) => { it('width', (done) => {
const vm = createVue({ const vm = createVue({
template: ` template: `

View File

@ -188,7 +188,7 @@ describe('Tabs', () => {
it('closable edge', done => { it('closable edge', done => {
vm = createVue({ vm = createVue({
template: ` template: `
<el-tabs type="card" :closable="true"> <el-tabs type="card" :closable="true" ref="tabs">
<el-tab-pane label="用户管理">A</el-tab-pane> <el-tab-pane label="用户管理">A</el-tab-pane>
<el-tab-pane label="配置管理">B</el-tab-pane> <el-tab-pane label="配置管理">B</el-tab-pane>
<el-tab-pane label="角色管理">C</el-tab-pane> <el-tab-pane label="角色管理">C</el-tab-pane>
@ -199,7 +199,7 @@ describe('Tabs', () => {
let tabList = vm.$el.querySelector('.el-tabs__header').children; let tabList = vm.$el.querySelector('.el-tabs__header').children;
let paneList = vm.$el.querySelector('.el-tabs__content').children; let paneList = vm.$el.querySelector('.el-tabs__content').children;
setTimeout(_ => { vm.$nextTick(_ => {
tabList[0].querySelector('.el-icon-close').click(); tabList[0].querySelector('.el-icon-close').click();
vm.$nextTick(_ => { vm.$nextTick(_ => {
expect(tabList.length).to.be.equal(3); expect(tabList.length).to.be.equal(3);
@ -209,16 +209,16 @@ describe('Tabs', () => {
tabList[2].click(); tabList[2].click();
tabList[2].querySelector('.el-icon-close').click(); tabList[2].querySelector('.el-icon-close').click();
vm.$nextTick(_ => { setTimeout(_ => {
expect(tabList.length).to.be.equal(2); expect(tabList.length).to.be.equal(2);
expect(paneList.length).to.be.equal(2); expect(paneList.length).to.be.equal(2);
expect(tabList[1].classList.contains('is-active')).to.be.true; expect(tabList[1].classList.contains('is-active')).to.be.true;
expect(tabList[1].innerText.trim()).to.be.equal('角色管理'); expect(tabList[1].innerText.trim()).to.be.equal('角色管理');
expect(paneList[1].innerText.trim()).to.be.equal('C'); expect(paneList[1].innerText.trim()).to.be.equal('C');
done(); done();
}); }, 100);
}); });
}, 100); });
}); });
it('tab title render function', done => { it('tab title render function', done => {
vm = createVue({ vm = createVue({

530
yarn.lock

File diff suppressed because it is too large Load Diff