add demo
parent
03664d73fb
commit
00522b0bba
|
@ -8,7 +8,7 @@ export default {
|
||||||
render (h) {
|
render (h) {
|
||||||
const inkBarNode = this.getInkBarNode()
|
const inkBarNode = this.getInkBarNode()
|
||||||
const tabs = this.getTabs(h)
|
const tabs = this.getTabs(h)
|
||||||
return this.getRootNode([inkBarNode, tabs])
|
return this.getRootNode([inkBarNode, tabs], h)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default {
|
||||||
const inkBarNode = this.getInkBarNode()
|
const inkBarNode = this.getInkBarNode()
|
||||||
const tabs = this.getTabs(h)
|
const tabs = this.getTabs(h)
|
||||||
const scrollbarNode = this.getScrollBarNode([inkBarNode, tabs])
|
const scrollbarNode = this.getScrollBarNode([inkBarNode, tabs])
|
||||||
return this.getRootNode(scrollbarNode)
|
return this.getRootNode(scrollbarNode, h)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,7 +9,7 @@ export default {
|
||||||
const inkBarNode = this.getInkBarNode()
|
const inkBarNode = this.getInkBarNode()
|
||||||
const tabs = this.getTabs(h)
|
const tabs = this.getTabs(h)
|
||||||
const scrollbarNode = this.getScrollBarNode([inkBarNode, tabs])
|
const scrollbarNode = this.getScrollBarNode([inkBarNode, tabs])
|
||||||
return this.getRootNode(scrollbarNode)
|
return this.getRootNode(scrollbarNode, h)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -27,20 +27,8 @@ export default {
|
||||||
this.resizeEvent = addDOMEventListener(window, 'resize', debouncedResize)
|
this.resizeEvent = addDOMEventListener(window, 'resize', debouncedResize)
|
||||||
},
|
},
|
||||||
|
|
||||||
updated (prevProps) {
|
updated () {
|
||||||
const props = this.$props
|
this.updatedCal()
|
||||||
if (prevProps && prevProps.tabBarPosition !== props.tabBarPosition) {
|
|
||||||
this.setOffset(0)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const nextPrev = this.setNextPrev()
|
|
||||||
// wait next, prev show hide
|
|
||||||
if (this.isNextPrevShown(this) !== this.isNextPrevShown(nextPrev)) {
|
|
||||||
Object.assign(this, this.scrollToActiveTab)
|
|
||||||
} else if (!prevProps || props.activeKey !== prevProps.activeKey) {
|
|
||||||
// can not use props.activeKey
|
|
||||||
this.scrollToActiveTab()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
|
@ -48,9 +36,17 @@ export default {
|
||||||
this.resizeEvent.remove()
|
this.resizeEvent.remove()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
tabBarPosition (val) {
|
||||||
|
this.setOffset(0)
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updatedCal () {
|
updatedCal () {
|
||||||
|
this.setNextPrev()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scrollToActiveTab()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
setNextPrev () {
|
setNextPrev () {
|
||||||
const navNode = this.$refs.nav
|
const navNode = this.$refs.nav
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Icon from '../icon'
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
prefixCls: {
|
prefixCls: {
|
||||||
|
@ -19,6 +20,16 @@ export default {
|
||||||
},
|
},
|
||||||
activeKey: String,
|
activeKey: String,
|
||||||
panels: Array,
|
panels: Array,
|
||||||
|
extraContent: [String, Number, Function],
|
||||||
|
hideAdd: Boolean,
|
||||||
|
removeTab: {
|
||||||
|
default: () => {},
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
createNewTab: {
|
||||||
|
default: () => {},
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getTabs (h) {
|
getTabs (h) {
|
||||||
|
@ -28,33 +39,46 @@ export default {
|
||||||
if (!child) {
|
if (!child) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let { disabled, closable } = child
|
||||||
|
const { tabKey, tab } = child
|
||||||
// componentOptions.propsData中获取的值disabled没有根据类型初始化, 会出现空字符串
|
// componentOptions.propsData中获取的值disabled没有根据类型初始化, 会出现空字符串
|
||||||
child.disabled = child.disabled === '' || child.disabled
|
disabled = disabled === '' || disabled
|
||||||
const key = child.tabKey
|
let cls = activeKey === tabKey ? `${prefixCls}-tab-active` : ''
|
||||||
let cls = activeKey === key ? `${prefixCls}-tab-active` : ''
|
|
||||||
cls += ` ${prefixCls}-tab`
|
cls += ` ${prefixCls}-tab`
|
||||||
if (child.disabled) {
|
if (disabled) {
|
||||||
cls += ` ${prefixCls}-tab-disabled`
|
cls += ` ${prefixCls}-tab-disabled`
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
!child.disabled && this.onTabClick(key)
|
!disabled && this.onTabClick(tabKey)
|
||||||
}
|
}
|
||||||
// const ref = {}
|
|
||||||
// if (activeKey === key) {
|
let tabC = typeof tab === 'function' ? child.tab(h, tabKey) : tab
|
||||||
// ref.ref = this.saveRef('activeTab')
|
if (this.$parent.type === 'editable-card') {
|
||||||
// }
|
closable = closable === undefined ? true : closable === '' || closable
|
||||||
|
const closeIcon = closable ? (
|
||||||
|
<Icon
|
||||||
|
type='close'
|
||||||
|
onClick={e => this.removeTab(tabKey, e)}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
tabC = <div class={closable ? undefined : `${prefixCls}-tab-unclosable`}>
|
||||||
|
{tabC}
|
||||||
|
{closeIcon}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
rst.push(
|
rst.push(
|
||||||
<div
|
<div
|
||||||
role='tab'
|
role='tab'
|
||||||
aria-disabled={child.disabled ? 'true' : 'false'}
|
aria-disabled={disabled ? 'true' : 'false'}
|
||||||
aria-selected={activeKey === key ? 'true' : 'false'}
|
aria-selected={activeKey === tabKey ? 'true' : 'false'}
|
||||||
class={cls}
|
class={cls}
|
||||||
key={key}
|
key={tabKey}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
ref={activeKey === key ? 'activeTab' : undefined}
|
ref={activeKey === tabKey ? 'activeTab' : undefined}
|
||||||
>
|
>
|
||||||
{typeof child.tab === 'function' ? child.tab(h, key) : child.tab}
|
{tabC}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -63,23 +87,35 @@ export default {
|
||||||
},
|
},
|
||||||
getRootNode (contents, createElement) {
|
getRootNode (contents, createElement) {
|
||||||
const {
|
const {
|
||||||
prefixCls, onKeyDown, tabBarPosition, $slots,
|
prefixCls, onKeyDown, tabBarPosition, hideAdd,
|
||||||
} = this
|
} = this
|
||||||
|
let extraContent = this.extraContent
|
||||||
|
const tabsType = this.$parent.type
|
||||||
const cls = {
|
const cls = {
|
||||||
[`${prefixCls}-bar`]: true,
|
[`${prefixCls}-bar`]: true,
|
||||||
}
|
}
|
||||||
const topOrBottom = (tabBarPosition === 'top' || tabBarPosition === 'bottom')
|
const topOrBottom = (tabBarPosition === 'top' || tabBarPosition === 'bottom')
|
||||||
const tabBarExtraContentStyle = topOrBottom ? { float: 'right' } : {}
|
const tabBarExtraContentStyle = topOrBottom ? { float: 'right' } : {}
|
||||||
let children = contents
|
let children = contents
|
||||||
if ($slots.default) {
|
extraContent = typeof extraContent === 'function' ? extraContent(createElement) : extraContent
|
||||||
|
|
||||||
|
if (tabsType === 'editable-card' && !hideAdd) {
|
||||||
|
extraContent = (
|
||||||
|
<span>
|
||||||
|
<Icon type='plus' class={`${prefixCls}-new-tab`} onClick={this.createNewTab} />
|
||||||
|
{extraContent}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
children = [
|
children = [
|
||||||
<div key='extra' class={`${prefixCls}-extra-content`} style={tabBarExtraContentStyle}>
|
<div key='extra' class={`${prefixCls}-extra-content`} style={tabBarExtraContentStyle}>
|
||||||
{$slots.default}
|
{extraContent}
|
||||||
</div>,
|
</div>,
|
||||||
contents,
|
contents,
|
||||||
]
|
]
|
||||||
children = topOrBottom ? children : children.reverse()
|
children = topOrBottom ? children : children.reverse()
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role='tablist'
|
role='tablist'
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
:aria-hidden="active ? 'false' : 'true'"
|
:aria-hidden="active ? 'false' : 'true'"
|
||||||
:class="classes"
|
:class="classes"
|
||||||
>
|
>
|
||||||
<slot v-if="isRender || forceRender">
|
<slot v-if="isRender">
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -14,12 +14,10 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
tabKey: [String, Number],
|
tabKey: [String, Number],
|
||||||
tab: [String, Number, Function],
|
tab: [String, Number, Function],
|
||||||
forceRender: Boolean,
|
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
// placeholder: [Function, String, Number],
|
closable: Boolean,
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
console.log(this.disabled)
|
|
||||||
return {
|
return {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,6 +45,13 @@ export default {
|
||||||
destroyInactiveTabPane: Boolean,
|
destroyInactiveTabPane: Boolean,
|
||||||
activeKey: String,
|
activeKey: String,
|
||||||
defaultActiveKey: String,
|
defaultActiveKey: String,
|
||||||
|
type: {
|
||||||
|
validator (value) {
|
||||||
|
return ['line', 'card', 'editable-card'].includes(value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onChange: { type: Function, default: () => {} },
|
||||||
|
onTabClick: { type: Function, default: () => {} },
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -79,11 +86,8 @@ export default {
|
||||||
}
|
}
|
||||||
return activeKey
|
return activeKey
|
||||||
},
|
},
|
||||||
onTabClick (activeKey) {
|
handleTabClick (activeKey) {
|
||||||
console.log('onTabClick', activeKey)
|
this.onTabClick(activeKey)
|
||||||
// if (this.tabBar.props.onTabClick) {
|
|
||||||
// this.tabBar.props.onTabClick(activeKey)
|
|
||||||
// }
|
|
||||||
this.setActiveKey(activeKey)
|
this.setActiveKey(activeKey)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -92,11 +96,11 @@ export default {
|
||||||
if (eventKeyCode === KeyCode.RIGHT || eventKeyCode === KeyCode.DOWN) {
|
if (eventKeyCode === KeyCode.RIGHT || eventKeyCode === KeyCode.DOWN) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const nextKey = this.getNextActiveKey(true)
|
const nextKey = this.getNextActiveKey(true)
|
||||||
this.onTabClick(nextKey)
|
this.handleTabClick(nextKey)
|
||||||
} else if (eventKeyCode === KeyCode.LEFT || eventKeyCode === KeyCode.UP) {
|
} else if (eventKeyCode === KeyCode.LEFT || eventKeyCode === KeyCode.UP) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const previousKey = this.getNextActiveKey(false)
|
const previousKey = this.getNextActiveKey(false)
|
||||||
this.onTabClick(previousKey)
|
this.handleTabClick(previousKey)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -105,8 +109,7 @@ export default {
|
||||||
if (!this.activeKey) {
|
if (!this.activeKey) {
|
||||||
this.stateActiveKey = activeKey
|
this.stateActiveKey = activeKey
|
||||||
}
|
}
|
||||||
// this.stateActiveKey = activeKey
|
this.onChange(activeKey)
|
||||||
this.$emit('change', activeKey)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -115,7 +118,7 @@ export default {
|
||||||
const children = []
|
const children = []
|
||||||
this.$slots.default.forEach(({ componentOptions = {}}) => {
|
this.$slots.default.forEach(({ componentOptions = {}}) => {
|
||||||
const c = componentOptions.propsData
|
const c = componentOptions.propsData
|
||||||
if (c && !c.disabled) {
|
if (c && !c.disabled && c.disabled !== '') {
|
||||||
if (next) {
|
if (next) {
|
||||||
children.push(c)
|
children.push(c)
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,7 +148,7 @@ export default {
|
||||||
tabBarPosition,
|
tabBarPosition,
|
||||||
destroyInactiveTabPane,
|
destroyInactiveTabPane,
|
||||||
onNavKeyDown,
|
onNavKeyDown,
|
||||||
onTabClick,
|
handleTabClick,
|
||||||
stateActiveKey,
|
stateActiveKey,
|
||||||
classes,
|
classes,
|
||||||
setActiveKey,
|
setActiveKey,
|
||||||
|
@ -176,16 +179,14 @@ export default {
|
||||||
prefixCls: prefixCls,
|
prefixCls: prefixCls,
|
||||||
onKeyDown: onNavKeyDown,
|
onKeyDown: onNavKeyDown,
|
||||||
tabBarPosition: tabBarPosition,
|
tabBarPosition: tabBarPosition,
|
||||||
onTabClick: onTabClick,
|
onTabClick: handleTabClick,
|
||||||
activeKey: stateActiveKey,
|
activeKey: stateActiveKey,
|
||||||
key: 'tabBar',
|
key: 'tabBar',
|
||||||
},
|
},
|
||||||
style: this.tabBarProps.style || {},
|
style: this.tabBarProps.style || {},
|
||||||
}
|
}
|
||||||
const contents = [
|
const contents = [
|
||||||
<ScrollableInkTabBar {...tabBarProps}>
|
<ScrollableInkTabBar {...tabBarProps} />,
|
||||||
{this.$slots.tabBarExtraContent}
|
|
||||||
</ScrollableInkTabBar>,
|
|
||||||
<TabContent {...tabContentProps}>
|
<TabContent {...tabContentProps}>
|
||||||
{$slots.default}
|
{$slots.default}
|
||||||
</TabContent>,
|
</TabContent>,
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<div class="card-container">
|
||||||
|
<Tabs type="card">
|
||||||
|
<TabPane tab="Tab Title 1" tabKey="1">
|
||||||
|
<p>Content of Tab Pane 1</p>
|
||||||
|
<p>Content of Tab Pane 1</p>
|
||||||
|
<p>Content of Tab Pane 1</p>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tab="Tab Title 2" tabKey="2">
|
||||||
|
<p>Content of Tab Pane 2</p>
|
||||||
|
<p>Content of Tab Pane 2</p>
|
||||||
|
<p>Content of Tab Pane 2</p>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tab="Tab Title 3" tabKey="3">
|
||||||
|
<p>Content of Tab Pane 3</p>
|
||||||
|
<p>Content of Tab Pane 3</p>
|
||||||
|
<p>Content of Tab Pane 3</p>
|
||||||
|
</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Tabs } from 'antd'
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
callback (key) {
|
||||||
|
console.log(key)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Tabs,
|
||||||
|
TabPane: Tabs.TabPane,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.card-container {
|
||||||
|
background: #F5F5F5;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
.card-container > .ant-tabs-card > .ant-tabs-content {
|
||||||
|
height: 120px;
|
||||||
|
margin-top: -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane {
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-container > .ant-tabs-card > .ant-tabs-bar {
|
||||||
|
border-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab {
|
||||||
|
border-color: transparent;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
|
||||||
|
border-color: #fff;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<Tabs @change="callback" type="card">
|
||||||
|
<TabPane tab="Tab 1" tabKey="1">Content of Tab Pane 1</TabPane>
|
||||||
|
<TabPane tab="Tab 2" tabKey="2">Content of Tab Pane 2</TabPane>
|
||||||
|
<TabPane tab="Tab 3" tabKey="3">Content of Tab Pane 3</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Tabs } from 'antd'
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
callback (key) {
|
||||||
|
console.log(key)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Tabs,
|
||||||
|
TabPane: Tabs.TabPane,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div :style="{ marginBottom: '16px' }">
|
||||||
|
<AntButton @click="add">ADD</AntButton>
|
||||||
|
</div>
|
||||||
|
<Tabs
|
||||||
|
hideAdd
|
||||||
|
v-model="activeKey"
|
||||||
|
type="editable-card"
|
||||||
|
@edit="onEdit"
|
||||||
|
>
|
||||||
|
<TabPane v-for="pane in panes" :tab="pane.title" :key="pane.key" :tabKey="pane.key" :closable="pane.closable">
|
||||||
|
{{pane.content}}
|
||||||
|
</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Tabs, Button } from 'antd'
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
const panes = [
|
||||||
|
{ title: 'Tab 1', content: 'Content of Tab 1', key: '1' },
|
||||||
|
{ title: 'Tab 2', content: 'Content of Tab 2', key: '2' },
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
activeKey: panes[0].key,
|
||||||
|
panes,
|
||||||
|
newTabIndex: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
callback (key) {
|
||||||
|
console.log(key)
|
||||||
|
},
|
||||||
|
onEdit (targetKey, action) {
|
||||||
|
this[action](targetKey)
|
||||||
|
},
|
||||||
|
add () {
|
||||||
|
const panes = this.panes
|
||||||
|
const activeKey = `newTab${this.newTabIndex++}`
|
||||||
|
panes.push({ title: 'New Tab', content: 'Content of new Tab', key: activeKey })
|
||||||
|
this.panes = panes
|
||||||
|
this.activeKey = activeKey
|
||||||
|
},
|
||||||
|
remove (targetKey) {
|
||||||
|
let activeKey = this.activeKey
|
||||||
|
let lastIndex
|
||||||
|
this.panes.forEach((pane, i) => {
|
||||||
|
if (pane.key === targetKey) {
|
||||||
|
lastIndex = i - 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const panes = this.panes.filter(pane => pane.key !== targetKey)
|
||||||
|
if (lastIndex >= 0 && activeKey === targetKey) {
|
||||||
|
activeKey = panes[lastIndex].key
|
||||||
|
}
|
||||||
|
this.panes = panes
|
||||||
|
this.activeKey = activeKey
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Tabs,
|
||||||
|
TabPane: Tabs.TabPane,
|
||||||
|
AntButton: Button,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,61 @@
|
||||||
|
<template>
|
||||||
|
<Tabs
|
||||||
|
v-model="activeKey"
|
||||||
|
type="editable-card"
|
||||||
|
@edit="onEdit"
|
||||||
|
>
|
||||||
|
<TabPane v-for="pane in panes" :tab="pane.title" :key="pane.key" :tabKey="pane.key" :closable="pane.closable">
|
||||||
|
{{pane.content}}
|
||||||
|
</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Tabs } from 'antd'
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
const panes = [
|
||||||
|
{ title: 'Tab 1', content: 'Content of Tab 1', key: '1', closable: false },
|
||||||
|
{ title: 'Tab 2', content: 'Content of Tab 2', key: '2' },
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
activeKey: panes[0].key,
|
||||||
|
panes,
|
||||||
|
newTabIndex: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
callback (key) {
|
||||||
|
console.log(key)
|
||||||
|
},
|
||||||
|
onEdit (targetKey, action) {
|
||||||
|
this[action](targetKey)
|
||||||
|
},
|
||||||
|
add () {
|
||||||
|
const panes = this.panes
|
||||||
|
const activeKey = `newTab${this.newTabIndex++}`
|
||||||
|
panes.push({ title: 'New Tab', content: 'Content of new Tab', key: activeKey })
|
||||||
|
this.panes = panes
|
||||||
|
this.activeKey = activeKey
|
||||||
|
},
|
||||||
|
remove (targetKey) {
|
||||||
|
let activeKey = this.activeKey
|
||||||
|
let lastIndex
|
||||||
|
this.panes.forEach((pane, i) => {
|
||||||
|
if (pane.key === targetKey) {
|
||||||
|
lastIndex = i - 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const panes = this.panes.filter(pane => pane.key !== targetKey)
|
||||||
|
if (lastIndex >= 0 && activeKey === targetKey) {
|
||||||
|
activeKey = panes[lastIndex].key
|
||||||
|
}
|
||||||
|
this.panes = panes
|
||||||
|
this.activeKey = activeKey
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Tabs,
|
||||||
|
TabPane: Tabs.TabPane,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<Tabs :tabBarExtraContent="operations">
|
||||||
|
<TabPane tab="Tab 1" tabKey="1">Content of tab 1</TabPane>
|
||||||
|
<TabPane tab="Tab 2" tabKey="2">Content of tab 2</TabPane>
|
||||||
|
<TabPane tab="Tab 3" tabKey="3">Content of tab 3</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Tabs, Button } from 'antd'
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
operations (h) {
|
||||||
|
return h('span', [<Button>Extra Action</Button>])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Tabs,
|
||||||
|
TabPane: Tabs.TabPane,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1>Basic</h1>
|
||||||
|
<Basic />
|
||||||
|
<h1>CardTop</h1>
|
||||||
|
<CardTop />
|
||||||
|
<h1>Card</h1>
|
||||||
|
<Card />
|
||||||
|
<h1>CustomAddTrigger</h1>
|
||||||
|
<CustomAddTrigger />
|
||||||
|
<h1>Disabled</h1>
|
||||||
|
<Disabled />
|
||||||
|
<h1>EditableCard</h1>
|
||||||
|
<EditableCard />
|
||||||
|
<h1>Extra</h1>
|
||||||
|
<Extra />
|
||||||
|
<h1>Icon</h1>
|
||||||
|
<Icon />
|
||||||
|
<h1>Position</h1>
|
||||||
|
<Position />
|
||||||
|
<h1>Size</h1>
|
||||||
|
<Size />
|
||||||
|
<h1>Slide</h1>
|
||||||
|
<Slide/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Basic from './basic'
|
||||||
|
import CardTop from './card-top'
|
||||||
|
import Card from './card'
|
||||||
|
import CustomAddTrigger from './custom-add-trigger'
|
||||||
|
import Disabled from './disabled'
|
||||||
|
import EditableCard from './editable-card'
|
||||||
|
import Extra from './extra'
|
||||||
|
import Icon from './icon'
|
||||||
|
import Position from './position'
|
||||||
|
import Size from './size'
|
||||||
|
import Slide from './slide'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Basic,
|
||||||
|
CardTop,
|
||||||
|
Card,
|
||||||
|
CustomAddTrigger,
|
||||||
|
Disabled,
|
||||||
|
EditableCard,
|
||||||
|
Extra,
|
||||||
|
Icon,
|
||||||
|
Position,
|
||||||
|
Size,
|
||||||
|
Slide,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<div style="width: 500px">
|
||||||
|
<RadioGroup v-model="tabPosition" style="margin:8px">
|
||||||
|
<RadioButton value="top">top</RadioButton>
|
||||||
|
<RadioButton value="bottom">bottom</RadioButton>
|
||||||
|
<RadioButton value="left">left</RadioButton>
|
||||||
|
<RadioButton value="right">right</RadioButton>
|
||||||
|
</RadioGroup>
|
||||||
|
<Tabs defaultActiveKey="1" :tabPosition="tabPosition">
|
||||||
|
<TabPane tab="Tab 1" tabKey="1">Content of Tab 1</TabPane>
|
||||||
|
<TabPane tab="Tab 2" tabKey="2">Content of Tab 2</TabPane>
|
||||||
|
<TabPane tab="Tab 3" tabKey="3">Content of Tab 3</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Tabs, Radio } from 'antd'
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
tabPosition: 'top',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
callback (val) {
|
||||||
|
console.log(val)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Tabs,
|
||||||
|
TabPane: Tabs.TabPane,
|
||||||
|
Radio,
|
||||||
|
RadioGroup: Radio.Group,
|
||||||
|
RadioButton: Radio.Button,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<Tabs defaultActiveKey="2" size="small">
|
||||||
|
<TabPane tab="Tab 1" tabKey="1">Content of tab 1</TabPane>
|
||||||
|
<TabPane tab="Tab 2" tabKey="2">Content of tab 2</TabPane>
|
||||||
|
<TabPane tab="Tab 3" tabKey="3">Content of tab 3</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Tabs } from 'antd'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Tabs,
|
||||||
|
TabPane: Tabs.TabPane,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="width: 500px">
|
<div style="width: 500px">
|
||||||
<RadioGroup v-model="mode" :style="{ marginBottom: 8 }">
|
<RadioGroup v-model="mode" :style="{ marginBottom: '8px' }">
|
||||||
<RadioButton value="top">Horizontal</RadioButton>
|
<RadioButton value="top">Horizontal</RadioButton>
|
||||||
<RadioButton value="left">Vertical</RadioButton>
|
<RadioButton value="left">Vertical</RadioButton>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
<Tabs defaultActiveKey="1" :tabPosition="mode" :style="{ height: '200px'}">
|
<Tabs defaultActiveKey="1" :tabPosition="mode" :style="{ height: '200px'}" @prevClick="callback" @nextClick="callback">
|
||||||
<TabPane tab="Tab 1" tabKey="1">Content of tab 1</TabPane>
|
<TabPane tab="Tab 1" tabKey="1">Content of tab 1</TabPane>
|
||||||
<TabPane tab="Tab 2" tabKey="2">Content of tab 2</TabPane>
|
<TabPane tab="Tab 2" tabKey="2">Content of tab 2</TabPane>
|
||||||
<TabPane tab="Tab 3" tabKey="3">Content of tab 3</TabPane>
|
<TabPane tab="Tab 3" tabKey="3">Content of tab 3</TabPane>
|
||||||
|
@ -29,6 +29,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
callback (val) {
|
||||||
|
console.log(val)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Tabs,
|
Tabs,
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import Tabs from './Tabs'
|
import Tabs from './Tabs'
|
||||||
// import TabPane from './TabPane'
|
|
||||||
import ScrollableInkTabBar from './ScrollableInkTabBar'
|
|
||||||
import TabBar from './TabBar'
|
|
||||||
import TabContent from './TabContent'
|
|
||||||
import Icon from '../icon'
|
|
||||||
import isFlexSupported from '../_util/isFlexSupported'
|
import isFlexSupported from '../_util/isFlexSupported'
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
@ -12,11 +7,9 @@ export default {
|
||||||
activeKey: String,
|
activeKey: String,
|
||||||
defaultActiveKey: String,
|
defaultActiveKey: String,
|
||||||
hideAdd: { type: Boolean, default: false },
|
hideAdd: { type: Boolean, default: false },
|
||||||
onChange: { type: Function, default: () => {} },
|
|
||||||
onTabClick: { type: Function, default: () => {} },
|
|
||||||
onPrevClick: { type: Function, default: () => {} },
|
|
||||||
onNextClick: { type: Function, default: () => {} },
|
|
||||||
tabBarStyle: Object,
|
tabBarStyle: Object,
|
||||||
|
tabBarExtraContent: [String, Number, Function],
|
||||||
|
destroyInactiveTabPane: { type: Boolean, default: false },
|
||||||
type: {
|
type: {
|
||||||
validator (value) {
|
validator (value) {
|
||||||
return ['line', 'card', 'editable-card'].includes(value)
|
return ['line', 'card', 'editable-card'].includes(value)
|
||||||
|
@ -27,20 +20,20 @@ export default {
|
||||||
return ['top', 'right', 'bottom', 'left'].includes(value)
|
return ['top', 'right', 'bottom', 'left'].includes(value)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onEdit: { type: Function, default: () => {} },
|
|
||||||
size: {
|
size: {
|
||||||
validator (value) {
|
validator (value) {
|
||||||
return ['default', 'small'].includes(value)
|
return ['default', 'small'].includes(value)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
animated: Boolean | Object,
|
animated: { type: [Boolean, Object], default: undefined },
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
prop: 'activeKey',
|
||||||
|
event: 'change',
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
createNewTab (targetKey) {
|
createNewTab (targetKey) {
|
||||||
const onEdit = this.$props.onEdit
|
this.$emit('edit', targetKey, 'add')
|
||||||
if (onEdit) {
|
|
||||||
onEdit(targetKey, 'add')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
removeTab (targetKey, e) {
|
removeTab (targetKey, e) {
|
||||||
|
@ -48,20 +41,21 @@ export default {
|
||||||
if (!targetKey) {
|
if (!targetKey) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
this.$emit('edit', targetKey, 'remove')
|
||||||
const onEdit = this.$props.onEdit
|
|
||||||
if (onEdit) {
|
|
||||||
onEdit(targetKey, 'remove')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleChange (activeKey) {
|
handleChange (activeKey) {
|
||||||
// const onChange = this.$props.onChange
|
|
||||||
// if (onChange) {
|
|
||||||
// onChange(activeKey)
|
|
||||||
// }
|
|
||||||
this.$emit('change', activeKey)
|
this.$emit('change', activeKey)
|
||||||
},
|
},
|
||||||
|
onTabClick (val) {
|
||||||
|
this.$emit('tabClick', val)
|
||||||
|
},
|
||||||
|
onPrevClick (val) {
|
||||||
|
this.$emit('prevClick', val)
|
||||||
|
},
|
||||||
|
onNextClick (val) {
|
||||||
|
this.$emit('nextClick', val)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted () {
|
mounted () {
|
||||||
|
@ -72,29 +66,32 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render () {
|
render (createElement) {
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
size,
|
size,
|
||||||
type = 'line',
|
type = 'line',
|
||||||
tabPosition,
|
tabPosition,
|
||||||
tabBarStyle,
|
tabBarStyle,
|
||||||
// hideAdd,
|
hideAdd,
|
||||||
onTabClick,
|
onTabClick,
|
||||||
onPrevClick,
|
onPrevClick,
|
||||||
onNextClick,
|
onNextClick,
|
||||||
animated = true,
|
animated,
|
||||||
} = this.$props
|
destroyInactiveTabPane = false,
|
||||||
let { tabBarExtraContent } = this.$props
|
activeKey,
|
||||||
|
defaultActiveKey,
|
||||||
|
} = this
|
||||||
|
const { tabBarExtraContent } = this.$props
|
||||||
let { inkBarAnimated, tabPaneAnimated } = typeof animated === 'object' ? { // eslint-disable-line
|
let { inkBarAnimated, tabPaneAnimated } = typeof animated === 'object' ? { // eslint-disable-line
|
||||||
inkBarAnimated: animated.inkBar, tabPaneAnimated: animated.tabPane,
|
inkBarAnimated: !!animated.inkBar, tabPaneAnimated: !!animated.tabPane,
|
||||||
} : {
|
} : {
|
||||||
inkBarAnimated: animated, tabPaneAnimated: animated,
|
inkBarAnimated: animated === undefined || animated, tabPaneAnimated: animated === undefined || animated,
|
||||||
}
|
}
|
||||||
|
|
||||||
// card tabs should not have animation
|
// card tabs should not have animation
|
||||||
if (type !== 'line') {
|
if (type !== 'line') {
|
||||||
tabPaneAnimated = 'animated' in this.$props ? tabPaneAnimated : false
|
tabPaneAnimated = animated === undefined ? false : tabPaneAnimated
|
||||||
}
|
}
|
||||||
const cls = {
|
const cls = {
|
||||||
[`${prefixCls}-mini`]: size === 'small' || size,
|
[`${prefixCls}-mini`]: size === 'small' || size,
|
||||||
|
@ -103,56 +100,7 @@ export default {
|
||||||
[`${prefixCls}-${type}`]: true,
|
[`${prefixCls}-${type}`]: true,
|
||||||
[`${prefixCls}-no-animation`]: !tabPaneAnimated,
|
[`${prefixCls}-no-animation`]: !tabPaneAnimated,
|
||||||
}
|
}
|
||||||
// only card type tabs can be added and closed
|
|
||||||
let childrenWithClose
|
|
||||||
// if (type === 'editable-card') {
|
|
||||||
// childrenWithClose = []
|
|
||||||
// React.Children.forEach(children, (child, index) => {
|
|
||||||
// let closable = child.props.closable
|
|
||||||
// closable = typeof closable === 'undefined' ? true : closable
|
|
||||||
// const closeIcon = closable ? (
|
|
||||||
// <Icon
|
|
||||||
// type='close'
|
|
||||||
// onClick={e => this.removeTab(child.key, e)}
|
|
||||||
// />
|
|
||||||
// ) : null
|
|
||||||
// childrenWithClose.push(cloneElement(child, {
|
|
||||||
// tab: (
|
|
||||||
// <div className={closable ? undefined : `${prefixCls}-tab-unclosable`}>
|
|
||||||
// {child.props.tab}
|
|
||||||
// {closeIcon}
|
|
||||||
// </div>
|
|
||||||
// ),
|
|
||||||
// key: child.key || index,
|
|
||||||
// }))
|
|
||||||
// })
|
|
||||||
// // Add new tab handler
|
|
||||||
// if (!hideAdd) {
|
|
||||||
// tabBarExtraContent = (
|
|
||||||
// <span>
|
|
||||||
// <Icon type='plus' className={`${prefixCls}-new-tab`} onClick={this.createNewTab} />
|
|
||||||
// {tabBarExtraContent}
|
|
||||||
// </span>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
tabBarExtraContent = tabBarExtraContent ? (
|
|
||||||
<div class={`${prefixCls}-extra-content`}>
|
|
||||||
{tabBarExtraContent}
|
|
||||||
</div>
|
|
||||||
) : null
|
|
||||||
|
|
||||||
// const renderTabBar = () => (
|
|
||||||
// <ScrollableInkTabBar
|
|
||||||
// inkBarAnimated={inkBarAnimated}
|
|
||||||
// extraContent={tabBarExtraContent}
|
|
||||||
// onTabClick={onTabClick}
|
|
||||||
// onPrevClick={onPrevClick}
|
|
||||||
// onNextClick={onNextClick}
|
|
||||||
// style={tabBarStyle}
|
|
||||||
// />
|
|
||||||
// )
|
|
||||||
const tabBarProps = {
|
const tabBarProps = {
|
||||||
inkBarAnimated,
|
inkBarAnimated,
|
||||||
extraContent: tabBarExtraContent,
|
extraContent: tabBarExtraContent,
|
||||||
|
@ -160,21 +108,40 @@ export default {
|
||||||
onPrevClick,
|
onPrevClick,
|
||||||
onNextClick,
|
onNextClick,
|
||||||
style: tabBarStyle,
|
style: tabBarStyle,
|
||||||
|
hideAdd,
|
||||||
|
removeTab: this.removeTab,
|
||||||
|
createNewTab: this.createNewTab,
|
||||||
}
|
}
|
||||||
const tabContentProps = {
|
const tabContentProps = {
|
||||||
animated: tabPaneAnimated,
|
animated: tabPaneAnimated,
|
||||||
animatedWithMargin: true,
|
animatedWithMargin: true,
|
||||||
}
|
}
|
||||||
|
const self = this
|
||||||
|
const tabsProps = {
|
||||||
|
props: {
|
||||||
|
prefixCls,
|
||||||
|
tabBarPosition: tabPosition,
|
||||||
|
onChange: this.handleChange,
|
||||||
|
tabBarProps: tabBarProps,
|
||||||
|
tabContentProps: tabContentProps,
|
||||||
|
destroyInactiveTabPane,
|
||||||
|
activeKey,
|
||||||
|
defaultActiveKey,
|
||||||
|
type,
|
||||||
|
onTabClick: this.onTabClick,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
change (val) {
|
||||||
|
self.handleChange(val)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
{...this.$props}
|
|
||||||
class={cls}
|
class={cls}
|
||||||
tabBarPosition={tabPosition}
|
{...tabsProps}
|
||||||
onChange={this.handleChange}
|
|
||||||
tabBarProps={tabBarProps}
|
|
||||||
tabContentProps={tabContentProps}
|
|
||||||
>
|
>
|
||||||
{childrenWithClose || this.$slots.default}
|
{this.$slots.default}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
---
|
||||||
|
category: Components
|
||||||
|
subtitle: 标签页
|
||||||
|
type: Data Display
|
||||||
|
title: Tabs
|
||||||
|
cols: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
选项卡切换组件。
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
提供平级的区域将大块内容进行收纳和展现,保持界面整洁。
|
||||||
|
|
||||||
|
Ant Design 依次提供了三级选项卡,分别用于不同的场景。
|
||||||
|
|
||||||
|
- 卡片式的页签,提供可关闭的样式,常用于容器顶部。
|
||||||
|
- 标准线条式页签,用于容器内部的主功能切换,这是最常用的 Tabs。
|
||||||
|
- [RadioButton](/components/radio/#components-radio-demo-radiobutton) 可作为更次级的页签来使用。
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Tabs
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| activeKey | 当前激活 tab 面板的 key | string | 无 |
|
||||||
|
| animated | 是否使用动画切换 Tabs,在 `tabPosition=top|bottom` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false |
|
||||||
|
| defaultActiveKey | 初始化选中面板的 key,如果没有设置 activeKey | string | 第一个面板 |
|
||||||
|
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false |
|
||||||
|
| size | 大小,提供 `default` 和 `small` 两种大小,仅当 `type="line"` 时生效。 | string | 'default' |
|
||||||
|
| tabBarExtraContent | tab bar 上额外的元素 | string\|number\|Function | 无 |
|
||||||
|
| tabBarStyle | tab bar 的样式对象 | object | - |
|
||||||
|
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | 'top' |
|
||||||
|
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | 'line' |
|
||||||
|
|
||||||
|
|
||||||
|
### 事件
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| change | 切换面板的回调 | Function | 无 |
|
||||||
|
| edit | 新增和删除页签的回调,在 `type="editable-card"` 时有效 | (targetKey, action): void | 无 |
|
||||||
|
| nextClick | next 按钮被点击的回调 | Function | 无 |
|
||||||
|
| prevClick | prev 按钮被点击的回调 | Function | 无 |
|
||||||
|
| tabClick | tab 被点击的回调 | Function | 无 |
|
||||||
|
|
||||||
|
### Tabs.TabPane
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false |
|
||||||
|
| tabKey | 对应 activeKey | string | 无 |
|
||||||
|
| tab | 选项卡头显示文字 | string\|Function | 无 |
|
Loading…
Reference in New Issue