pull/9/head
tangjinzhou 2017-12-01 18:48:16 +08:00
parent 03664d73fb
commit 00522b0bba
18 changed files with 555 additions and 149 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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'

View File

@ -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 {
} }
}, },

View File

@ -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>,

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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,

View File

@ -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>
) )
}, },

View File

@ -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 | 无 |