Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
Element
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
CI / CD Analytics
Repository Analytics
Value Stream Analytics
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
林焕东
Element
Commits
0bec05ad
Commit
0bec05ad
authored
Jan 12, 2017
by
baiyaaaaa
Committed by
杨奕
Feb 04, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update tab api
parent
14565178
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
619 additions
and
179 deletions
+619
-179
examples/docs/en-US/tabs.md
examples/docs/en-US/tabs.md
+210
-37
examples/docs/zh-CN/tabs.md
examples/docs/zh-CN/tabs.md
+200
-41
packages/tabs/src/tabs.vue
packages/tabs/src/tabs.vue
+34
-51
packages/theme-default/src/tabs.css
packages/theme-default/src/tabs.css
+22
-0
test/unit/specs/tabs.spec.js
test/unit/specs/tabs.spec.js
+153
-50
No files found.
examples/docs/en-US/tabs.md
View file @
0bec05ad
...
...
@@ -2,9 +2,20 @@
export default {
data() {
return {
activeName: '
first
',
activeName: '
second
',
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',
name: '1',
content: 'Tab 1 content'
...
...
@@ -17,11 +28,62 @@
}
},
methods: {
handleRemove(tab) {
console.log(tab);
},
handleClick(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 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
| Attribute | Description | Type | Accepted Values | Default |
|---------- |-------- |---------- |------------- |-------- |
| type | type of Tab | string | card/border-card | — |
| 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 |
| 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 |
|---------- |-------- |---------- |
| 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
| Attribute | Description | Type | Accepted Values | Default |
...
...
examples/docs/zh-CN/tabs.md
View file @
0bec05ad
...
...
@@ -4,7 +4,18 @@
return {
activeName: 'second',
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',
name: '1',
content: 'Tab 1 content'
...
...
@@ -17,11 +28,62 @@
}
},
methods: {
handleRemove(tab) {
console.log(tab);
},
handleClick(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
```
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>
<el-button
size=
"small"
@
click=
"addTab(editableTabsValue2)"
>
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
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>
```
:::
...
...
@@ -178,14 +333,18 @@
|---------- |-------- |---------- |------------- |-------- |
| type | 风格类型 | string | card/border-card | — |
| closable | 标签是否可关闭 | boolean | — | false |
| addable | 标签是否可增加 | boolean | — | false |
| editable | 标签是否同时可增加和关闭 | boolean | — | false |
| active-name(deprecated) | 选中选项卡的 name | string | — | 第一个选项卡的 name |
| value | 绑定值,选中选项卡的 name | string | — | 第一个选项卡的 name |
### Tabs Events
| 事件名称 | 说明 | 回调参数 |
|---------- |-------- |---------- |
| tab-click | tab 被选中的钩子 | 被选中的标签 tab 实例 |
| tab-remove | tab 被删除的钩子 | 被删除的标签 tab 实例 |
| tab-click | tab 被选中时触发 | 被选中的标签 tab 实例 |
| tab-remove | 点击 tab 移除按钮后触发 | 被删除的标签的 name |
| tab-add | 点击 tabs 的新增按钮后触发 | — |
| edit | 点击 tabs 的新增按钮或 tab 被关闭后触发 | (targetName, action) |
### Tab-pane Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
...
...
packages/tabs/src/tabs.vue
View file @
0bec05ad
...
...
@@ -10,11 +10,10 @@
props
:
{
type
:
String
,
activeName
:
String
,
closable
:
{
type
:
Boolean
,
default
:
false
},
value
:
{}
closable
:
Boolean
,
addable
:
Boolean
,
value
:
{},
editable
:
Boolean
},
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
:
{
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
)
{
if
(
tab
.
disabled
)
return
;
this
.
setCurrentName
(
tabName
);
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
)
{
this
.
currentName
=
value
;
this
.
$emit
(
'
input
'
,
value
);
...
...
@@ -100,21 +66,37 @@
render
(
h
)
{
let
{
type
,
handleTabRemove
,
handleTabClick
,
handleTabRemove
,
handleTabAdd
,
currentName
,
panes
panes
,
editable
,
addable
}
=
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
)
=>
{
let
tabName
=
pane
.
name
||
pane
.
index
||
index
;
const
closable
=
pane
.
isClosable
||
editable
;
if
(
currentName
===
undefined
&&
index
===
0
)
{
this
.
setCurrentName
(
tabName
);
}
pane
.
index
=
index
;
const
btnClose
=
pane
.
isC
losable
const
btnClose
=
c
losable
?
<
span
class
=
"
el-icon-close
"
on
-
click
=
{(
ev
)
=>
{
handleTabRemove
(
pane
,
ev
);
}}
><
/span
>
:
null
;
...
...
@@ -125,7 +107,7 @@
'
el-tabs__item
'
:
true
,
'
is-active
'
:
pane
.
active
,
'
is-disabled
'
:
pane
.
disabled
,
'
is-closable
'
:
pane
.
isC
losable
'
is-closable
'
:
c
losable
}}
ref
=
"
tabs
"
refInFor
...
...
@@ -146,6 +128,7 @@
<
div
class
=
"
el-tabs__header
"
>
{
!
type
?
<
tab
-
bar
tabs
=
{
panes
}
><
/tab-bar> : null
}
{
tabs
}
{
newButton
}
<
/div
>
<
div
class
=
"
el-tabs__content
"
>
{
this
.
$slots
.
default
}
...
...
packages/theme-default/src/tabs.css
View file @
0bec05ad
...
...
@@ -20,6 +20,28 @@
transition
:
transform
.3s
cubic-bezier
(
.645
,
.045
,
.355
,
1
);
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
{
padding
:
0
16px
;
height
:
42px
;
...
...
test/unit/specs/tabs.spec.js
View file @
0bec05ad
...
...
@@ -140,33 +140,172 @@ describe('Tabs', () => {
});
},
100
);
});
it
(
'
clos
able
'
,
done
=>
{
it
(
'
edit
able
'
,
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 ref="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>
`
`
,
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
);
let
spy
=
sinon
.
spy
();
vm
.
$refs
.
tabs
.
$on
(
'
tab-remove
'
,
spy
);
setTimeout
(
_
=>
{
const
tabList
=
vm
.
$refs
.
tabs
.
$refs
.
tabs
;
const
paneList
=
vm
.
$el
.
querySelector
(
'
.el-tabs__content
'
).
children
;
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
(
_
=>
{
expect
(
tabList
.
length
).
to
.
be
.
equal
(
3
);
expect
(
paneList
.
length
).
to
.
be
.
equal
(
3
);
expect
(
spy
.
calledOnce
).
to
.
true
;
expect
(
tabList
[
1
].
innerText
.
trim
()).
to
.
be
.
equal
(
'
角色管理
'
);
expect
(
paneList
[
0
].
innerText
.
trim
()).
to
.
be
.
equal
(
'
A
'
);
done
();
expect
(
tabList
[
2
].
classList
.
contains
(
'
is-active
'
)).
to
.
be
.
true
;
tabList
[
2
].
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
;
done
();
});
});
},
100
);
});
...
...
@@ -187,42 +326,6 @@ describe('Tabs', () => {
done
();
},
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
=>
{
vm
=
createVue
({
template
:
`
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment