This commit is contained in:
tangjinzhou 2017-11-21 19:15:41 +08:00
parent b0a21a5b08
commit 3b6008151b
11 changed files with 437 additions and 3 deletions

View File

@ -23,3 +23,5 @@ export { default as Tag } from './tag'
export { default as Avatar } from './avatar' export { default as Avatar } from './avatar'
export { default as Badge } from './badge' export { default as Badge } from './badge'
export { default as Tabs } from './tabs'

View File

@ -8,3 +8,4 @@ import './rate/style'
import './pagination/style' import './pagination/style'
import './avatar/style' import './avatar/style'
import './badge/style' import './badge/style'
import './tabs/style'

View File

@ -0,0 +1,18 @@
export default {
/**
* LEFT
*/
LEFT: 37, // also NUM_WEST
/**
* UP
*/
UP: 38, // also NUM_NORTH
/**
* RIGHT
*/
RIGHT: 39, // also NUM_EAST
/**
* DOWN
*/
DOWN: 40, // also NUM_SOUTH
}

View File

@ -0,0 +1,7 @@
export default {
saveRef (name) {
return node => {
this[name] = node
}
},
}

View File

@ -0,0 +1,75 @@
<template>
<button :class="classes" :disabled="disabled"
@click="handleClick" @mouseout="mouseout" @mouseover="mouseover">
{{tab}}
</button>
</template>
<script>
export default {
name: 'TabBar',
props: {
prefixCls: {
default: 'ant-tabs',
type: String,
},
tabBarPosition: {
default: 'top',
validator (value) {
return ['top', 'bottom'].includes(value)
},
},
disabled: Boolean,
onKeyDown: Function,
onTabClick: Function,
activeKey: String,
tab: String,
},
data () {
return {
sizeMap: {
large: 'lg',
small: 'sm',
},
clicked: false,
}
},
computed: {
classes () {
const { prefixCls, type, shape, size, loading, ghost, clicked, sizeMap } = this
const sizeCls = sizeMap[size] || ''
return {
[`${prefixCls}`]: true,
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-${shape}`]: shape,
[`${prefixCls}-${sizeCls}`]: sizeCls,
[`${prefixCls}-loading`]: loading,
[`${prefixCls}-clicked`]: clicked,
[`${prefixCls}-background-ghost`]: ghost || type === 'ghost',
}
},
},
methods: {
handleClick (event) {
if (this.clicked) {
return
}
this.clicked = true
clearTimeout(this.timeout)
this.timeout = setTimeout(() => (this.clicked = false), 500)
this.$emit('click', event)
},
mouseover (event) {
this.$emit('mouseover', event)
},
mouseout (event) {
this.$emit('mouseout', event)
},
},
beforeDestroy () {
if (this.timeout) {
clearTimeout(this.timeout)
}
},
}
</script>

View File

@ -0,0 +1,66 @@
<script>
import {
getTransformByIndex,
getActiveIndex,
getTransformPropValue,
getMarginStyle,
} from './utils'
export default {
name: 'TabContent',
props: {
animated: { type: Boolean, default: true },
animatedWithMargin: { type: Boolean, default: true },
prefixCls: {
default: 'ant-tabs',
type: String,
},
activeKey: String,
tabBarPosition: String,
},
data () {
return {
}
},
computed: {
classes () {
const { animated, prefixCls } = this
return {
[`${prefixCls}-content`]: true,
[animated
? `${prefixCls}-content-animated`
: `${prefixCls}-content-no-animated`]: true,
}
},
},
methods: {
},
render () {
const {
activeKey,
tabBarPosition, animated, animatedWithMargin, classes,
} = this
let style = {}
if (animated && this.$slots.default) {
const activeIndex = getActiveIndex(this.$slots.default, activeKey)
if (activeIndex !== -1) {
const animatedStyle = animatedWithMargin
? getMarginStyle(activeIndex, tabBarPosition)
: getTransformPropValue(getTransformByIndex(activeIndex, tabBarPosition))
style = animatedStyle
} else {
style = {
display: 'none',
}
}
}
return (
<div
class={classes}
style={style}
>
{this.$slots.default}
</div>
)
},
}
</script>

View File

@ -0,0 +1,48 @@
<template>
<div
role="tabpanel"
:aria-hidden="active ? 'false' : 'true'"
:class="classes"
>
<slot v-if="isRender || forceRender">
</slot>
</div>
</template>
<script>
export default {
name: 'TabPane',
props: {
pKey: [String, Number],
forceRender: Boolean,
// placeholder: [Function, String, Number],
},
data () {
const { prefixCls, destroyInactiveTabPane, activeKey } = this.$parent
return {
rootPrefixCls: prefixCls,
destroyInactiveTabPane,
active: this.pKey === activeKey,
}
},
computed: {
classes () {
const { rootPrefixCls, active } = this
const prefixCls = `${rootPrefixCls}-tabpane`
return {
[`${prefixCls}`]: true,
[`${prefixCls}-inactive`]: !active,
[`${prefixCls}-active`]: active,
}
},
isRender () {
const {
destroyInactiveTabPane, active,
} = this
this._isActived = this._isActived || active
return destroyInactiveTabPane ? active : this._isActived
},
},
methods: {
},
}
</script>

View File

@ -0,0 +1,174 @@
<script>
import Icon from '../icon'
import KeyCode from './KeyCode'
import TabBar from './TabBar'
import TabContent from './TabContent'
function getDefaultActiveKey (t) {
let activeKey
t.$slot.default.forEach((child) => {
if (child && !activeKey && !child.disabled) {
activeKey = child.pKey
}
})
return activeKey
}
function activeKeyIsValid (t, key) {
const keys = t.$slot.default.map(child => child && child.pKey)
return keys.indexOf(key) >= 0
}
export default {
name: 'Tabs',
components: { Icon },
props: {
prefixCls: {
default: 'ant-tabs',
type: String,
},
tabBarPosition: {
default: 'top',
validator (value) {
return ['top', 'bottom'].includes(value)
},
},
destroyInactiveTabPane: Boolean,
activeKey: String,
defaultActiveKey: String,
},
data () {
return {
stateActiveKey: this.getStateActiveKey(),
}
},
computed: {
classes () {
const { prefixCls, tabBarPosition } = this
return {
[`${prefixCls}`]: true,
[`${prefixCls}-${tabBarPosition}`]: true,
}
},
},
beforeUpdate () {
if ('activeKey' in this) {
this.stateActiveKey = this.activeKey
} else if (!activeKeyIsValid(this, this.stateActiveKey)) {
this.stateActiveKey = getDefaultActiveKey(this)
}
},
methods: {
getStateActiveKey () {
let activeKey
if ('activeKey' in this) {
activeKey = this.activeKey
} else if ('defaultActiveKey' in this) {
activeKey = this.defaultActiveKey
} else {
activeKey = getDefaultActiveKey(this)
}
return activeKey
},
onTabClick (activeKey) {
if (this.tabBar.props.onTabClick) {
this.tabBar.props.onTabClick(activeKey)
}
this.setActiveKey(activeKey)
},
onNavKeyDown (e) {
const eventKeyCode = e.keyCode
if (eventKeyCode === KeyCode.RIGHT || eventKeyCode === KeyCode.DOWN) {
e.preventDefault()
const nextKey = this.getNextActiveKey(true)
this.onTabClick(nextKey)
} else if (eventKeyCode === KeyCode.LEFT || eventKeyCode === KeyCode.UP) {
e.preventDefault()
const previousKey = this.getNextActiveKey(false)
this.onTabClick(previousKey)
}
},
setActiveKey (activeKey) {
if (this.stateActiveKey !== activeKey) {
if (!('activeKey' in this)) {
this.stateActiveKey = activeKey
}
this.$emit('change', activeKey)
}
},
getNextActiveKey (next) {
const activeKey = this.stateActiveKey
const children = []
this.$slot.default.forEach((c) => {
if (c && !c.disabled) {
if (next) {
children.push(c)
} else {
children.unshift(c)
}
}
})
const length = children.length
let ret = length && children[0].key
children.forEach((child, i) => {
if (child.pKey === activeKey) {
if (i === length - 1) {
ret = children[0].key
} else {
ret = children[i + 1].key
}
}
})
return ret
},
},
beforeDestroy () {
},
render () {
const {
prefixCls,
tabBarPosition,
destroyInactiveTabPane,
onNavKeyDown,
onTabClick,
stateActiveKey,
classes,
setActiveKey,
$slots,
} = this
const hasSlot = !!$slots.default
const tabBarProps = []
if (hasSlot) {
$slots.default.forEach(tab => {
tab.data && tabBarProps.push(
<TabBar
{...tab.data}
prefixCls={prefixCls}
onKeyDown={onNavKeyDown}
tabBarPosition={tabBarPosition}
onTabClick={onTabClick}
activeKey={stateActiveKey} />)
})
}
const tabContentProps = {
props: {
prefixCls,
tabBarPosition,
activeKey: stateActiveKey,
destroyInactiveTabPane,
onChange: setActiveKey,
key: 'tabContent',
}}
return (
<div
class={classes}
>
{tabBarProps}
<TabContent {...tabContentProps}>
{$slots.default}
</TabContent>
</div>
)
},
}
</script>

View File

@ -0,0 +1,17 @@
<template>
<div>
<Tabs activeKey="test1">
<TabPane pKey="test1" tab="tab1">hello</TabPane>
<TabPane pKey="test2" tab="tab2">world</TabPane>
</Tabs>
</div>
</template>
<script>
import { Tabs } from 'antd'
export default {
components: {
Tabs,
TabPane: Tabs.TabPane,
},
}
</script>

View File

@ -1,6 +1,6 @@
import Tabs from './Tabs' import Tabs from './Tabs'
import TabPane from './TabPane' import TabPane from './TabPane'
import TabContent from './TabContent' // import TabContent from './TabContent'
Tabs.TabPane = TabPane
export default Tabs export default Tabs
export { TabPane, TabContent } export { TabPane }

View File

@ -1,3 +1,29 @@
export function toArray (children) {
// allow [c,[a,b]]
const c = []
children.forEach(child => {
if (child.data) {
c.push(child)
}
})
return c
}
export function getActiveIndex (children, activeKey) {
const c = toArray(children)
for (let i = 0; i < c.length; i++) {
const pKey = c[i].pKey || c[i].componentOptions.propsData.pKey
if (pKey === activeKey) {
return i
}
}
return -1
}
export function getActiveKey (children, index) {
const c = toArray(children)
return c[index].pKey
}
export function setTransform (style, v) { export function setTransform (style, v) {
style.transform = v style.transform = v