mirror of https://github.com/ElemeFE/element
update tab api
parent
14565178ed
commit
0bec05ada3
|
@ -2,9 +2,20 @@
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeName: 'first',
|
activeName: 'second',
|
||||||
activeName2: 'first',
|
activeName2: 'first',
|
||||||
tabs: [{
|
editableTabsValue: '2',
|
||||||
|
editableTabsValue2: '2',
|
||||||
|
editableTabs: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}],
|
||||||
|
editableTabs2: [{
|
||||||
title: 'Tab 1',
|
title: 'Tab 1',
|
||||||
name: '1',
|
name: '1',
|
||||||
content: 'Tab 1 content'
|
content: 'Tab 1 content'
|
||||||
|
@ -17,11 +28,62 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleRemove(tab) {
|
|
||||||
console.log(tab);
|
|
||||||
},
|
|
||||||
handleClick(tab, event) {
|
handleClick(tab, event) {
|
||||||
console.log(tab, event);
|
console.log(tab, event);
|
||||||
|
},
|
||||||
|
handleTabsEdit(targetName, action) {
|
||||||
|
if (action === 'add') {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue = newTabName;
|
||||||
|
}
|
||||||
|
if (action === 'remove') {
|
||||||
|
let tabs = this.editableTabs;
|
||||||
|
let activeName = this.editableTabsValue;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue = activeName;
|
||||||
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addTab(targetName) {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs2.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue2 = newTabName;
|
||||||
|
},
|
||||||
|
removeTab(targetName) {
|
||||||
|
let tabs = this.editableTabs2;
|
||||||
|
let activeName = this.editableTabsValue2;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue2 = activeName;
|
||||||
|
this.editableTabs2 = tabs.filter(tab => tab.name !== targetName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,37 +157,6 @@ Tabs styled as cards.
|
||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Closable
|
|
||||||
|
|
||||||
Closable tabs.
|
|
||||||
|
|
||||||
:::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
|
|
||||||
<template>
|
|
||||||
<el-tabs type="card" :closable="true" @tab-click="handleClick" @tab-remove="handleRemove">
|
|
||||||
<el-tab-pane label="User">User</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>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
methods: {
|
|
||||||
handleRemove(tab) {
|
|
||||||
console.log(tab);
|
|
||||||
},
|
|
||||||
handleClick(tab, event) {
|
|
||||||
console.log(tab, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
### Border card
|
### Border card
|
||||||
|
|
||||||
Border card tabs.
|
Border card tabs.
|
||||||
|
@ -161,11 +192,151 @@ You can use named slot to customize the tab label content.
|
||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
### Add & close tab
|
||||||
|
|
||||||
|
Only card type Tabs support addable & closeable.
|
||||||
|
|
||||||
|
:::demo
|
||||||
|
```html
|
||||||
|
<el-tabs v-model="editableTabsValue" type="card" editable @edit="handleTabsEdit">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="(item, index) in editableTabs"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
>
|
||||||
|
{{item.content}}
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editableTabsValue: '2',
|
||||||
|
editableTabs: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}],
|
||||||
|
tabIndex: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTabsEdit(targetName, action) {
|
||||||
|
if (action === 'add') {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue = newTabName;
|
||||||
|
}
|
||||||
|
if (action === 'remove') {
|
||||||
|
let tabs = this.editableTabs;
|
||||||
|
let activeName = this.editableTabsValue;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue = activeName;
|
||||||
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
### Customized trigger button of new tab
|
||||||
|
|
||||||
|
:::demo
|
||||||
|
```html
|
||||||
|
<div style="margin-bottom: 20px;">
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
@click="addTab(editableTabsValue2)"
|
||||||
|
>
|
||||||
|
add tab
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-tabs v-model="editableTabsValue2" type="card" closable @tab-remove="removeTab">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="(item, index) in editableTabs2"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
>
|
||||||
|
{{item.content}}
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editableTabsValue2: '2',
|
||||||
|
editableTabs2: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}],
|
||||||
|
tabIndex: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addTab(targetName) {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs2.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue2 = newTabName;
|
||||||
|
},
|
||||||
|
removeTab(targetName) {
|
||||||
|
let tabs = this.editableTabs2;
|
||||||
|
let activeName = this.editableTabsValue2;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue2 = activeName;
|
||||||
|
this.editableTabs2 = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</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 |
|
||||||
|
| addable | whether Tab is addable | boolean | — | false |
|
||||||
|
| editable | whether Tab is addable and closable | boolean | — | false |
|
||||||
| active-name(deprecated) | 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 |
|
| value | name of the selected tab | string | — | name of first tab |
|
||||||
|
|
||||||
|
@ -173,7 +344,9 @@ You can use named slot to customize the tab label content.
|
||||||
| Event Name | Description | Parameters |
|
| Event Name | Description | Parameters |
|
||||||
|---------- |-------- |---------- |
|
|---------- |-------- |---------- |
|
||||||
| tab-click | triggers when a tab is clicked | clicked tab |
|
| tab-click | triggers when a tab is clicked | clicked tab |
|
||||||
| tab-remove | triggers when a tab is removed | removed tab |
|
| tab-remove | triggers when tab-remove button is clicked | name of the removed tab |
|
||||||
|
| tab-add | triggers when tab-add button is clicked | — |
|
||||||
|
| edit | triggers when tab-add button or tab-remove is clicked | (targetName, action) |
|
||||||
|
|
||||||
### Tab-pane Attributes
|
### Tab-pane Attributes
|
||||||
| Attribute | Description | Type | Accepted Values | Default |
|
| Attribute | Description | Type | Accepted Values | Default |
|
||||||
|
|
|
@ -4,7 +4,18 @@
|
||||||
return {
|
return {
|
||||||
activeName: 'second',
|
activeName: 'second',
|
||||||
activeName2: 'first',
|
activeName2: 'first',
|
||||||
tabs: [{
|
editableTabsValue: '2',
|
||||||
|
editableTabsValue2: '2',
|
||||||
|
editableTabs: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}],
|
||||||
|
editableTabs2: [{
|
||||||
title: 'Tab 1',
|
title: 'Tab 1',
|
||||||
name: '1',
|
name: '1',
|
||||||
content: 'Tab 1 content'
|
content: 'Tab 1 content'
|
||||||
|
@ -17,11 +28,62 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleRemove(tab) {
|
|
||||||
console.log(tab);
|
|
||||||
},
|
|
||||||
handleClick(tab, event) {
|
handleClick(tab, event) {
|
||||||
console.log(tab, event);
|
console.log(tab, event);
|
||||||
|
},
|
||||||
|
handleTabsEdit(targetName, action) {
|
||||||
|
if (action === 'add') {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue = newTabName;
|
||||||
|
}
|
||||||
|
if (action === 'remove') {
|
||||||
|
let tabs = this.editableTabs;
|
||||||
|
let activeName = this.editableTabsValue;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue = activeName;
|
||||||
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addTab(targetName) {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs2.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue2 = newTabName;
|
||||||
|
},
|
||||||
|
removeTab(targetName) {
|
||||||
|
let tabs = this.editableTabs2;
|
||||||
|
let activeName = this.editableTabsValue2;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue2 = activeName;
|
||||||
|
this.editableTabs2 = tabs.filter(tab => tab.name !== targetName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,36 +157,6 @@
|
||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### 可关闭
|
|
||||||
|
|
||||||
可以关闭标签页。
|
|
||||||
|
|
||||||
:::demo 通过设置 `closable` 属性来打开 `Tabs` 的可关闭标签效果, `closable` 也可以设置在 `Tab Panel` 中实现部分标签页的可关闭效果。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<template>
|
|
||||||
<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-tabs>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
methods: {
|
|
||||||
handleRemove(tab) {
|
|
||||||
console.log(tab);
|
|
||||||
},
|
|
||||||
handleClick(tab, event) {
|
|
||||||
console.log(tab, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
:::
|
|
||||||
|
|
||||||
### 卡片化
|
### 卡片化
|
||||||
|
|
||||||
卡片化的标签页。
|
卡片化的标签页。
|
||||||
|
@ -158,18 +190,141 @@
|
||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### 动态增加标签页
|
### 动态增减标签页
|
||||||
|
|
||||||
展示如何通过触发器来动态增加标签页
|
增减标签页按钮只能在选项卡样式的标签页下使用
|
||||||
|
|
||||||
|
:::demo
|
||||||
|
```html
|
||||||
|
<el-tabs v-model="editableTabsValue" type="card" editable @edit="handleTabsEdit">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="(item, index) in editableTabs"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
>
|
||||||
|
{{item.content}}
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editableTabsValue: '2',
|
||||||
|
editableTabs: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}],
|
||||||
|
tabIndex: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTabsEdit(targetName, action) {
|
||||||
|
if (action === 'add') {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue = newTabName;
|
||||||
|
}
|
||||||
|
if (action === 'remove') {
|
||||||
|
let tabs = this.editableTabs;
|
||||||
|
let activeName = this.editableTabsValue;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue = activeName;
|
||||||
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
### 自定义增加标签页触发器
|
||||||
|
|
||||||
:::demo
|
:::demo
|
||||||
```html
|
```html
|
||||||
<div style="margin-bottom: 20px;">
|
<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>
|
<el-button
|
||||||
|
size="small"
|
||||||
|
@click="addTab(editableTabsValue2)"
|
||||||
|
>
|
||||||
|
add tab
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-tabs type="card" closable>
|
<el-tabs v-model="editableTabsValue2" type="card" closable @tab-remove="removeTab">
|
||||||
<el-tab-pane v-for="(item, index) in tabs" :label="item.title" :name="item.name">{{item.content}}</el-tab-pane>
|
<el-tab-pane
|
||||||
|
v-for="(item, index) in editableTabs2"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
>
|
||||||
|
{{item.content}}
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editableTabsValue2: '2',
|
||||||
|
editableTabs2: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}],
|
||||||
|
tabIndex: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addTab(targetName) {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs2.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue2 = newTabName;
|
||||||
|
},
|
||||||
|
removeTab(targetName) {
|
||||||
|
let tabs = this.editableTabs2;
|
||||||
|
let activeName = this.editableTabsValue2;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editableTabsValue2 = activeName;
|
||||||
|
this.editableTabs2 = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
@ -178,14 +333,18 @@
|
||||||
|---------- |-------- |---------- |------------- |-------- |
|
|---------- |-------- |---------- |------------- |-------- |
|
||||||
| type | 风格类型 | string | card/border-card | — |
|
| type | 风格类型 | string | card/border-card | — |
|
||||||
| closable | 标签是否可关闭 | boolean | — | false |
|
| closable | 标签是否可关闭 | boolean | — | false |
|
||||||
|
| addable | 标签是否可增加 | boolean | — | false |
|
||||||
|
| editable | 标签是否同时可增加和关闭 | boolean | — | false |
|
||||||
| active-name(deprecated) | 选中选项卡的 name | string | — | 第一个选项卡的 name |
|
| active-name(deprecated) | 选中选项卡的 name | string | — | 第一个选项卡的 name |
|
||||||
| value | 绑定值,选中选项卡的 name | string | — | 第一个选项卡的 name |
|
| value | 绑定值,选中选项卡的 name | string | — | 第一个选项卡的 name |
|
||||||
|
|
||||||
### Tabs Events
|
### Tabs Events
|
||||||
| 事件名称 | 说明 | 回调参数 |
|
| 事件名称 | 说明 | 回调参数 |
|
||||||
|---------- |-------- |---------- |
|
|---------- |-------- |---------- |
|
||||||
| tab-click | tab 被选中的钩子 | 被选中的标签 tab 实例 |
|
| tab-click | tab 被选中时触发 | 被选中的标签 tab 实例 |
|
||||||
| tab-remove | tab 被删除的钩子 | 被删除的标签 tab 实例 |
|
| tab-remove | 点击 tab 移除按钮后触发 | 被删除的标签的 name |
|
||||||
|
| tab-add | 点击 tabs 的新增按钮后触发 | — |
|
||||||
|
| edit | 点击 tabs 的新增按钮或 tab 被关闭后触发 | (targetName, action) |
|
||||||
|
|
||||||
### Tab-pane Attributes
|
### Tab-pane Attributes
|
||||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|
||||||
|
|
|
@ -10,11 +10,10 @@
|
||||||
props: {
|
props: {
|
||||||
type: String,
|
type: String,
|
||||||
activeName: String,
|
activeName: String,
|
||||||
closable: {
|
closable: Boolean,
|
||||||
type: Boolean,
|
addable: Boolean,
|
||||||
default: false
|
value: {},
|
||||||
},
|
editable: Boolean
|
||||||
value: {}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@ -34,54 +33,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
|
||||||
currentTab() {
|
|
||||||
let result;
|
|
||||||
this.panes.forEach(tab => {
|
|
||||||
if (this.currentName === (tab.name || tab.index)) {
|
|
||||||
result = tab;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleTabRemove(pane, event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const panes = this.panes;
|
|
||||||
const currentTab = this.currentTab;
|
|
||||||
|
|
||||||
let index = panes.indexOf(pane);
|
|
||||||
|
|
||||||
if (index === -1) return;
|
|
||||||
|
|
||||||
panes.splice(index, 1);
|
|
||||||
pane.$destroy();
|
|
||||||
|
|
||||||
this.$emit('tab-remove', pane);
|
|
||||||
|
|
||||||
this.$nextTick(_ => {
|
|
||||||
if (pane.active) {
|
|
||||||
const panes = this.panes;
|
|
||||||
let nextChild = panes[index];
|
|
||||||
let prevChild = panes[index - 1];
|
|
||||||
let nextActiveTab = nextChild || prevChild || null;
|
|
||||||
|
|
||||||
if (nextActiveTab) {
|
|
||||||
this.setCurrentName(nextActiveTab.name || nextActiveTab.index);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.setCurrentName(currentTab.name || currentTab.index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleTabClick(tab, tabName, event) {
|
handleTabClick(tab, tabName, event) {
|
||||||
if (tab.disabled) return;
|
if (tab.disabled) return;
|
||||||
this.setCurrentName(tabName);
|
this.setCurrentName(tabName);
|
||||||
this.$emit('tab-click', tab, event);
|
this.$emit('tab-click', tab, event);
|
||||||
},
|
},
|
||||||
|
handleTabRemove(pane, ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.$emit('edit', pane.name, 'remove');
|
||||||
|
this.$emit('tab-remove', pane.name);
|
||||||
|
},
|
||||||
|
handleTabAdd() {
|
||||||
|
this.$emit('edit', null, 'add');
|
||||||
|
this.$emit('tab-add');
|
||||||
|
},
|
||||||
setCurrentName(value) {
|
setCurrentName(value) {
|
||||||
this.currentName = value;
|
this.currentName = value;
|
||||||
this.$emit('input', value);
|
this.$emit('input', value);
|
||||||
|
@ -100,21 +66,37 @@
|
||||||
render(h) {
|
render(h) {
|
||||||
let {
|
let {
|
||||||
type,
|
type,
|
||||||
handleTabRemove,
|
|
||||||
handleTabClick,
|
handleTabClick,
|
||||||
|
handleTabRemove,
|
||||||
|
handleTabAdd,
|
||||||
currentName,
|
currentName,
|
||||||
panes
|
panes,
|
||||||
|
editable,
|
||||||
|
addable
|
||||||
} = this;
|
} = this;
|
||||||
|
|
||||||
|
const newButton = editable || addable
|
||||||
|
? (
|
||||||
|
<span
|
||||||
|
class="el-tabs__new-button"
|
||||||
|
on-click={ handleTabAdd }
|
||||||
|
>
|
||||||
|
<i class="el-icon-plus"></i>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
const tabs = this._l(panes, (pane, index) => {
|
const tabs = this._l(panes, (pane, index) => {
|
||||||
let tabName = pane.name || pane.index || index;
|
let tabName = pane.name || pane.index || index;
|
||||||
|
const closable = pane.isClosable || editable;
|
||||||
|
|
||||||
if (currentName === undefined && index === 0) {
|
if (currentName === undefined && index === 0) {
|
||||||
this.setCurrentName(tabName);
|
this.setCurrentName(tabName);
|
||||||
}
|
}
|
||||||
|
|
||||||
pane.index = index;
|
pane.index = index;
|
||||||
|
|
||||||
const btnClose = pane.isClosable
|
const btnClose = closable
|
||||||
? <span class="el-icon-close" on-click={(ev) => { handleTabRemove(pane, ev); }}></span>
|
? <span class="el-icon-close" on-click={(ev) => { handleTabRemove(pane, ev); }}></span>
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
@ -125,7 +107,7 @@
|
||||||
'el-tabs__item': true,
|
'el-tabs__item': true,
|
||||||
'is-active': pane.active,
|
'is-active': pane.active,
|
||||||
'is-disabled': pane.disabled,
|
'is-disabled': pane.disabled,
|
||||||
'is-closable': pane.isClosable
|
'is-closable': closable
|
||||||
}}
|
}}
|
||||||
ref="tabs"
|
ref="tabs"
|
||||||
refInFor
|
refInFor
|
||||||
|
@ -146,6 +128,7 @@
|
||||||
<div class="el-tabs__header">
|
<div class="el-tabs__header">
|
||||||
{!type ? <tab-bar tabs={panes}></tab-bar> : null}
|
{!type ? <tab-bar tabs={panes}></tab-bar> : null}
|
||||||
{tabs}
|
{tabs}
|
||||||
|
{newButton}
|
||||||
</div>
|
</div>
|
||||||
<div class="el-tabs__content">
|
<div class="el-tabs__content">
|
||||||
{this.$slots.default}
|
{this.$slots.default}
|
||||||
|
|
|
@ -20,6 +20,28 @@
|
||||||
transition: transform .3s cubic-bezier(.645,.045,.355,1);
|
transition: transform .3s cubic-bezier(.645,.045,.355,1);
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
@e new-button {
|
||||||
|
float: left;
|
||||||
|
border: 1px solid #d3dce6;
|
||||||
|
height: 18px;
|
||||||
|
width: @height;
|
||||||
|
line-height: @height;
|
||||||
|
margin: 12px 0 9px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #d3dce6;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all .15s;
|
||||||
|
|
||||||
|
.el-icon-plus {
|
||||||
|
transform: scale(0.8, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
@e item {
|
@e item {
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
|
|
|
@ -140,33 +140,172 @@ describe('Tabs', () => {
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
it('closable', done => {
|
it('editable', done => {
|
||||||
vm = createVue({
|
vm = createVue({
|
||||||
template: `
|
template: `
|
||||||
<el-tabs type="card" :closable="true" ref="tabs">
|
<el-tabs ref="tabs" v-model="editableTabsValue" type="card" editable @edit="handleTabsEdit">
|
||||||
<el-tab-pane label="用户管理">A</el-tab-pane>
|
<el-tab-pane
|
||||||
<el-tab-pane label="配置管理">B</el-tab-pane>
|
v-for="(item, index) in editableTabs"
|
||||||
<el-tab-pane label="角色管理">C</el-tab-pane>
|
:label="item.title"
|
||||||
<el-tab-pane label="定时任务补偿">D</el-tab-pane>
|
:name="item.name"
|
||||||
|
>
|
||||||
|
{{item.content}}
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
`
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editableTabsValue: '2',
|
||||||
|
editableTabs: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 3',
|
||||||
|
name: '3',
|
||||||
|
content: 'Tab 3 content'
|
||||||
|
}],
|
||||||
|
tabIndex: 3
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTabsEdit(targetName, action) {
|
||||||
|
if (action === 'add') {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue = newTabName;
|
||||||
|
}
|
||||||
|
if (action === 'remove') {
|
||||||
|
let tabs = this.editableTabs;
|
||||||
|
let activeName = this.editableTabsValue;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.editableTabsValue = activeName;
|
||||||
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
let spy = sinon.spy();
|
|
||||||
vm.$refs.tabs.$on('tab-remove', spy);
|
|
||||||
|
|
||||||
setTimeout(_ => {
|
setTimeout(_ => {
|
||||||
const tabList = vm.$refs.tabs.$refs.tabs;
|
const tabList = vm.$refs.tabs.$refs.tabs;
|
||||||
const paneList = vm.$el.querySelector('.el-tabs__content').children;
|
const paneList = vm.$el.querySelector('.el-tabs__content').children;
|
||||||
|
|
||||||
tabList[1].querySelector('.el-icon-close').click();
|
tabList[1].querySelector('.el-icon-close').click();
|
||||||
|
vm.$nextTick(_ => {
|
||||||
|
expect(tabList.length).to.be.equal(2);
|
||||||
|
expect(paneList.length).to.be.equal(2);
|
||||||
|
expect(tabList[1].classList.contains('is-active')).to.be.true;
|
||||||
|
|
||||||
|
vm.$refs.tabs.$el.querySelector('.el-tabs__new-button').click();
|
||||||
|
vm.$nextTick(_ => {
|
||||||
|
expect(tabList.length).to.be.equal(3);
|
||||||
|
expect(paneList.length).to.be.equal(3);
|
||||||
|
expect(tabList[2].classList.contains('is-active')).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
it('addable & closable', done => {
|
||||||
|
vm = createVue({
|
||||||
|
template: `
|
||||||
|
<el-tabs
|
||||||
|
ref="tabs"
|
||||||
|
v-model="editableTabsValue"
|
||||||
|
type="card"
|
||||||
|
addable
|
||||||
|
closable
|
||||||
|
@tab-add="addTab"
|
||||||
|
@tab-remove="removeTab"
|
||||||
|
>
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="(item, index) in editableTabs"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
>
|
||||||
|
{{item.content}}
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editableTabsValue: '2',
|
||||||
|
editableTabs: [{
|
||||||
|
title: 'Tab 1',
|
||||||
|
name: '1',
|
||||||
|
content: 'Tab 1 content'
|
||||||
|
}, {
|
||||||
|
title: 'Tab 2',
|
||||||
|
name: '2',
|
||||||
|
content: 'Tab 2 content'
|
||||||
|
}],
|
||||||
|
tabIndex: 2
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addTab(targetName) {
|
||||||
|
let newTabName = ++this.tabIndex + '';
|
||||||
|
this.editableTabs.push({
|
||||||
|
title: 'New Tab',
|
||||||
|
name: newTabName,
|
||||||
|
content: 'New Tab content'
|
||||||
|
});
|
||||||
|
this.editableTabsValue = newTabName;
|
||||||
|
},
|
||||||
|
removeTab(targetName) {
|
||||||
|
let tabs = this.editableTabs;
|
||||||
|
let activeName = this.editableTabsValue;
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.editableTabsValue = activeName;
|
||||||
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
setTimeout(_ => {
|
||||||
|
const tabList = vm.$refs.tabs.$refs.tabs;
|
||||||
|
const paneList = vm.$el.querySelector('.el-tabs__content').children;
|
||||||
|
|
||||||
|
vm.$refs.tabs.$el.querySelector('.el-tabs__new-button').click();
|
||||||
|
|
||||||
vm.$nextTick(_ => {
|
vm.$nextTick(_ => {
|
||||||
expect(tabList.length).to.be.equal(3);
|
expect(tabList.length).to.be.equal(3);
|
||||||
expect(paneList.length).to.be.equal(3);
|
expect(paneList.length).to.be.equal(3);
|
||||||
expect(spy.calledOnce).to.true;
|
expect(tabList[2].classList.contains('is-active')).to.be.true;
|
||||||
expect(tabList[1].innerText.trim()).to.be.equal('角色管理');
|
|
||||||
expect(paneList[0].innerText.trim()).to.be.equal('A');
|
tabList[2].querySelector('.el-icon-close').click();
|
||||||
done();
|
vm.$nextTick(_ => {
|
||||||
|
expect(tabList.length).to.be.equal(2);
|
||||||
|
expect(paneList.length).to.be.equal(2);
|
||||||
|
expect(tabList[1].classList.contains('is-active')).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
|
@ -187,42 +326,6 @@ describe('Tabs', () => {
|
||||||
done();
|
done();
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
it('closable edge', done => {
|
|
||||||
vm = createVue({
|
|
||||||
template: `
|
|
||||||
<el-tabs type="card" :closable="true" ref="tabs">
|
|
||||||
<el-tab-pane label="用户管理">A</el-tab-pane>
|
|
||||||
<el-tab-pane label="配置管理">B</el-tab-pane>
|
|
||||||
<el-tab-pane label="角色管理">C</el-tab-pane>
|
|
||||||
<el-tab-pane label="定时任务补偿">D</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
`
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
vm.$nextTick(_ => {
|
|
||||||
const paneList = vm.$el.querySelector('.el-tabs__content').children;
|
|
||||||
const tabList = vm.$refs.tabs.$refs.tabs;
|
|
||||||
|
|
||||||
tabList[0].querySelector('.el-icon-close').click();
|
|
||||||
vm.$nextTick(_ => {
|
|
||||||
expect(tabList.length).to.be.equal(3);
|
|
||||||
expect(paneList.length).to.be.equal(3);
|
|
||||||
expect(tabList[0].innerText.trim()).to.be.equal('配置管理');
|
|
||||||
expect(paneList[0].innerText.trim()).to.be.equal('B');
|
|
||||||
|
|
||||||
tabList[2].click();
|
|
||||||
tabList[2].querySelector('.el-icon-close').click();
|
|
||||||
setTimeout(_ => {
|
|
||||||
expect(tabList.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].innerText.trim()).to.be.equal('角色管理');
|
|
||||||
expect(paneList[1].innerText.trim()).to.be.equal('C');
|
|
||||||
done();
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('disabled', done => {
|
it('disabled', done => {
|
||||||
vm = createVue({
|
vm = createVue({
|
||||||
template: `
|
template: `
|
||||||
|
|
Loading…
Reference in New Issue