fix
parent
eb021ff40c
commit
b1f8fd739f
|
@ -0,0 +1,14 @@
|
||||||
|
<script>
|
||||||
|
import InkTabBarMixin from './InkTabBarMixin'
|
||||||
|
import TabBarMixin from './TabBarMixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'InkTabBar',
|
||||||
|
mixins: [TabBarMixin, InkTabBarMixin],
|
||||||
|
render () {
|
||||||
|
const inkBarNode = this.getInkBarNode()
|
||||||
|
const tabs = this.getTabs()
|
||||||
|
return this.getRootNode([inkBarNode, tabs])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,146 @@
|
||||||
|
import { setTransform, isTransformSupported } from './utils'
|
||||||
|
|
||||||
|
export function getScroll (w, top) {
|
||||||
|
let ret = w[`page${top ? 'Y' : 'X'}Offset`]
|
||||||
|
const method = `scroll${top ? 'Top' : 'Left'}`
|
||||||
|
if (typeof ret !== 'number') {
|
||||||
|
const d = w.document
|
||||||
|
// ie6,7,8 standard mode
|
||||||
|
ret = d.documentElement[method]
|
||||||
|
if (typeof ret !== 'number') {
|
||||||
|
// quirks mode
|
||||||
|
ret = d.body[method]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
function offset (elem) {
|
||||||
|
let x
|
||||||
|
let y
|
||||||
|
const doc = elem.ownerDocument
|
||||||
|
const body = doc.body
|
||||||
|
const docElem = doc && doc.documentElement
|
||||||
|
const box = elem.getBoundingClientRect()
|
||||||
|
x = box.left
|
||||||
|
y = box.top
|
||||||
|
x -= docElem.clientLeft || body.clientLeft || 0
|
||||||
|
y -= docElem.clientTop || body.clientTop || 0
|
||||||
|
const w = doc.defaultView || doc.parentWindow
|
||||||
|
x += getScroll(w)
|
||||||
|
y += getScroll(w, true)
|
||||||
|
return {
|
||||||
|
left: x, top: y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function componentDidUpdate (component, init) {
|
||||||
|
const { styles } = component.$props
|
||||||
|
const wrapNode = component.$refs.nav || component.$refs.root
|
||||||
|
const containerOffset = offset(wrapNode)
|
||||||
|
const inkBarNode = component.$refs.inkBar
|
||||||
|
const activeTab = component.$refs.activeTab
|
||||||
|
const inkBarNodeStyle = inkBarNode.style
|
||||||
|
const tabBarPosition = component.$props.tabBarPosition
|
||||||
|
if (init) {
|
||||||
|
// prevent mount animation
|
||||||
|
inkBarNodeStyle.display = 'none'
|
||||||
|
}
|
||||||
|
if (activeTab) {
|
||||||
|
const tabNode = activeTab
|
||||||
|
const tabOffset = offset(tabNode)
|
||||||
|
const transformSupported = isTransformSupported(inkBarNodeStyle)
|
||||||
|
if (tabBarPosition === 'top' || tabBarPosition === 'bottom') {
|
||||||
|
let left = tabOffset.left - containerOffset.left
|
||||||
|
let width = tabNode.offsetWidth
|
||||||
|
|
||||||
|
// If tabNode'width width equal to wrapNode'width when tabBarPosition is top or bottom
|
||||||
|
// It means no css working, then ink bar should not have width until css is loaded
|
||||||
|
// Fix https://github.com/ant-design/ant-design/issues/7564
|
||||||
|
if (width === wrapNode.offsetWidth) {
|
||||||
|
width = 0
|
||||||
|
} else if (styles.inkBar && styles.inkBar.width !== undefined) {
|
||||||
|
width = parseFloat(styles.inkBar.width, 10)
|
||||||
|
if (width) {
|
||||||
|
left = left + (tabNode.offsetWidth - width) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// use 3d gpu to optimize render
|
||||||
|
if (transformSupported) {
|
||||||
|
setTransform(inkBarNodeStyle, `translate3d(${left}px,0,0)`)
|
||||||
|
inkBarNodeStyle.width = `${width}px`
|
||||||
|
inkBarNodeStyle.height = ''
|
||||||
|
} else {
|
||||||
|
inkBarNodeStyle.left = `${left}px`
|
||||||
|
inkBarNodeStyle.top = ''
|
||||||
|
inkBarNodeStyle.bottom = ''
|
||||||
|
inkBarNodeStyle.right = `${wrapNode.offsetWidth - left - width}px`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let top = tabOffset.top - containerOffset.top
|
||||||
|
let height = tabNode.offsetHeight
|
||||||
|
if (styles.inkBar && styles.inkBar.height !== undefined) {
|
||||||
|
height = parseFloat(styles.inkBar.height, 10)
|
||||||
|
if (height) {
|
||||||
|
top = top + (tabNode.offsetHeight - height) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (transformSupported) {
|
||||||
|
setTransform(inkBarNodeStyle, `translate3d(0,${top}px,0)`)
|
||||||
|
inkBarNodeStyle.height = `${height}px`
|
||||||
|
inkBarNodeStyle.width = ''
|
||||||
|
} else {
|
||||||
|
inkBarNodeStyle.left = ''
|
||||||
|
inkBarNodeStyle.right = ''
|
||||||
|
inkBarNodeStyle.top = `${top}px`
|
||||||
|
inkBarNodeStyle.bottom = `${wrapNode.offsetHeight - top - height}px`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inkBarNodeStyle.display = activeTab ? 'block' : 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
inkBarAnimated: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
prefixCls: String,
|
||||||
|
styles: Object,
|
||||||
|
},
|
||||||
|
updated () {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
componentDidUpdate(this, true)
|
||||||
|
})
|
||||||
|
componentDidUpdate(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
componentDidUpdate(this, true)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getInkBarNode () {
|
||||||
|
const { prefixCls, styles = {}, inkBarAnimated } = this
|
||||||
|
const className = `${prefixCls}-ink-bar`
|
||||||
|
const classes = {
|
||||||
|
[className]: true,
|
||||||
|
[
|
||||||
|
inkBarAnimated
|
||||||
|
? `${className}-animated`
|
||||||
|
: `${className}-no-animated`
|
||||||
|
]: true,
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={styles.inkBar}
|
||||||
|
class={classes}
|
||||||
|
key='inkBar'
|
||||||
|
ref='inkBar'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script>
|
||||||
|
import InkTabBarMixin from './InkTabBarMixin'
|
||||||
|
import ScrollableTabBarMixin from './ScrollableTabBarMixin'
|
||||||
|
import TabBarMixin from './TabBarMixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ScrollableInkTabBar',
|
||||||
|
mixins: [TabBarMixin, InkTabBarMixin, ScrollableTabBarMixin],
|
||||||
|
render () {
|
||||||
|
const inkBarNode = this.getInkBarNode()
|
||||||
|
const tabs = this.getTabs()
|
||||||
|
const scrollbarNode = this.getScrollBarNode([inkBarNode, tabs])
|
||||||
|
return this.getRootNode(scrollbarNode)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script>
|
||||||
|
import ScrollableTabBarMixin from './ScrollableTabBarMixin'
|
||||||
|
import TabBarMixin from './TabBarMixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ScrollableTabBar',
|
||||||
|
mixins: [TabBarMixin, ScrollableTabBarMixin],
|
||||||
|
render () {
|
||||||
|
const inkBarNode = this.getInkBarNode()
|
||||||
|
const tabs = this.getTabs()
|
||||||
|
const scrollbarNode = this.getScrollBarNode([inkBarNode, tabs])
|
||||||
|
return this.getRootNode(scrollbarNode)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
|
@ -0,0 +1,288 @@
|
||||||
|
import { setTransform, isTransformSupported } from './utils'
|
||||||
|
import addDOMEventListener from 'add-dom-event-listener'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
function noop () {
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
scrollAnimated: { type: Boolean, default: true },
|
||||||
|
onPrevClick: { type: Function, default: noop },
|
||||||
|
onNextClick: { type: Function, default: noop },
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
next: false,
|
||||||
|
prev: false,
|
||||||
|
offset: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
this.updatedCal()
|
||||||
|
const debouncedResize = debounce(() => {
|
||||||
|
this.setNextPrev()
|
||||||
|
this.scrollToActiveTab()
|
||||||
|
}, 200)
|
||||||
|
this.resizeEvent = addDOMEventListener(window, 'resize', debouncedResize)
|
||||||
|
},
|
||||||
|
|
||||||
|
updated (prevProps) {
|
||||||
|
const props = this.$props
|
||||||
|
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 () {
|
||||||
|
if (this.resizeEvent) {
|
||||||
|
this.resizeEvent.remove()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updatedCal () {
|
||||||
|
|
||||||
|
},
|
||||||
|
setNextPrev () {
|
||||||
|
const navNode = this.nav
|
||||||
|
const navNodeWH = this.getOffsetWH(navNode)
|
||||||
|
const navWrapNode = this.navWrap
|
||||||
|
const navWrapNodeWH = this.getOffsetWH(navWrapNode)
|
||||||
|
let { offset } = this
|
||||||
|
const minOffset = navWrapNodeWH - navNodeWH
|
||||||
|
let { next, prev } = this
|
||||||
|
if (minOffset >= 0) {
|
||||||
|
next = false
|
||||||
|
this.setOffset(0, false)
|
||||||
|
offset = 0
|
||||||
|
} else if (minOffset < offset) {
|
||||||
|
next = (true)
|
||||||
|
} else {
|
||||||
|
next = (false)
|
||||||
|
this.setOffset(minOffset, false)
|
||||||
|
offset = minOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset < 0) {
|
||||||
|
prev = (true)
|
||||||
|
} else {
|
||||||
|
prev = (false)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setNext(next)
|
||||||
|
this.setPrev(prev)
|
||||||
|
return {
|
||||||
|
next,
|
||||||
|
prev,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getOffsetWH (node) {
|
||||||
|
const tabBarPosition = this.$props.tabBarPosition
|
||||||
|
let prop = 'offsetWidth'
|
||||||
|
if (tabBarPosition === 'left' || tabBarPosition === 'right') {
|
||||||
|
prop = 'offsetHeight'
|
||||||
|
}
|
||||||
|
return node[prop]
|
||||||
|
},
|
||||||
|
|
||||||
|
getOffsetLT (node) {
|
||||||
|
const tabBarPosition = this.$props.tabBarPosition
|
||||||
|
let prop = 'left'
|
||||||
|
if (tabBarPosition === 'left' || tabBarPosition === 'right') {
|
||||||
|
prop = 'top'
|
||||||
|
}
|
||||||
|
return node.getBoundingClientRect()[prop]
|
||||||
|
},
|
||||||
|
|
||||||
|
setOffset (offset, checkNextPrev = true) {
|
||||||
|
const target = Math.min(0, offset)
|
||||||
|
if (this.offset !== target) {
|
||||||
|
this.offset = target
|
||||||
|
let navOffset = {}
|
||||||
|
const tabBarPosition = this.$props.tabBarPosition
|
||||||
|
const navStyle = this.nav.style
|
||||||
|
const transformSupported = isTransformSupported(navStyle)
|
||||||
|
if (tabBarPosition === 'left' || tabBarPosition === 'right') {
|
||||||
|
if (transformSupported) {
|
||||||
|
navOffset = {
|
||||||
|
value: `translate3d(0,${target}px,0)`,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navOffset = {
|
||||||
|
name: 'top',
|
||||||
|
value: `${target}px`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (transformSupported) {
|
||||||
|
navOffset = {
|
||||||
|
value: `translate3d(${target}px,0,0)`,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navOffset = {
|
||||||
|
name: 'left',
|
||||||
|
value: `${target}px`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (transformSupported) {
|
||||||
|
setTransform(navStyle, navOffset.value)
|
||||||
|
} else {
|
||||||
|
navStyle[navOffset.name] = navOffset.value
|
||||||
|
}
|
||||||
|
if (checkNextPrev) {
|
||||||
|
this.setNextPrev()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setPrev (v) {
|
||||||
|
if (this.prev !== v) {
|
||||||
|
this.prev = v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setNext (v) {
|
||||||
|
if (this.next !== v) {
|
||||||
|
this.next = v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isNextPrevShown (state) {
|
||||||
|
if (state) {
|
||||||
|
return state.next || state.prev
|
||||||
|
}
|
||||||
|
return this.next || this.prev
|
||||||
|
},
|
||||||
|
|
||||||
|
prevTransitionEnd (e) {
|
||||||
|
if (e.propertyName !== 'opacity') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { container } = this
|
||||||
|
this.scrollToActiveTab({
|
||||||
|
target: container,
|
||||||
|
currentTarget: container,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollToActiveTab (e) {
|
||||||
|
const { activeTab, navWrap } = this
|
||||||
|
if (e && e.target !== e.currentTarget || !activeTab) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// when not scrollable or enter scrollable first time, don't emit scrolling
|
||||||
|
const needToSroll = this.isNextPrevShown() && this.lastNextPrevShown
|
||||||
|
this.lastNextPrevShown = this.isNextPrevShown()
|
||||||
|
if (!needToSroll) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeTabWH = this.getOffsetWH(activeTab)
|
||||||
|
const navWrapNodeWH = this.getOffsetWH(navWrap)
|
||||||
|
let { offset } = this
|
||||||
|
const wrapOffset = this.getOffsetLT(navWrap)
|
||||||
|
const activeTabOffset = this.getOffsetLT(activeTab)
|
||||||
|
if (wrapOffset > activeTabOffset) {
|
||||||
|
offset += (wrapOffset - activeTabOffset)
|
||||||
|
this.setOffset(offset)
|
||||||
|
} else if ((wrapOffset + navWrapNodeWH) < (activeTabOffset + activeTabWH)) {
|
||||||
|
offset -= (activeTabOffset + activeTabWH) - (wrapOffset + navWrapNodeWH)
|
||||||
|
this.setOffset(offset)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
prevClick (e) {
|
||||||
|
this.$props.onPrevClick(e)
|
||||||
|
const navWrapNode = this.navWrap
|
||||||
|
const navWrapNodeWH = this.getOffsetWH(navWrapNode)
|
||||||
|
const { offset } = this
|
||||||
|
this.setOffset(offset + navWrapNodeWH)
|
||||||
|
},
|
||||||
|
|
||||||
|
nextClick (e) {
|
||||||
|
this.$props.onNextClick(e)
|
||||||
|
const navWrapNode = this.navWrap
|
||||||
|
const navWrapNodeWH = this.getOffsetWH(navWrapNode)
|
||||||
|
const { offset } = this
|
||||||
|
this.setOffset(offset - navWrapNodeWH)
|
||||||
|
},
|
||||||
|
|
||||||
|
getScrollBarNode (content) {
|
||||||
|
const { next, prev } = this
|
||||||
|
const { prefixCls, scrollAnimated } = this.$props
|
||||||
|
const showNextPrev = prev || next
|
||||||
|
|
||||||
|
const prevButton = (
|
||||||
|
<span
|
||||||
|
onClick={prev ? this.prevClick : noop}
|
||||||
|
unselectable='unselectable'
|
||||||
|
class={{
|
||||||
|
[`${prefixCls}-tab-prev`]: 1,
|
||||||
|
[`${prefixCls}-tab-btn-disabled`]: !prev,
|
||||||
|
[`${prefixCls}-tab-arrow-show`]: showNextPrev,
|
||||||
|
}}
|
||||||
|
onTransitionEnd={this.prevTransitionEnd}
|
||||||
|
>
|
||||||
|
<span class={`${prefixCls}-tab-prev-icon`} />
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
const nextButton = (
|
||||||
|
<span
|
||||||
|
onClick={next ? this.nextClick : noop}
|
||||||
|
unselectable='unselectable'
|
||||||
|
class={{
|
||||||
|
[`${prefixCls}-tab-next`]: 1,
|
||||||
|
[`${prefixCls}-tab-btn-disabled`]: !next,
|
||||||
|
[`${prefixCls}-tab-arrow-show`]: showNextPrev,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class={`${prefixCls}-tab-next-icon`} />
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
const navClassName = `${prefixCls}-nav`
|
||||||
|
const navClasses = {
|
||||||
|
[navClassName]: true,
|
||||||
|
[
|
||||||
|
scrollAnimated
|
||||||
|
? `${navClassName}-animated`
|
||||||
|
: `${navClassName}-no-animated`
|
||||||
|
]: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={{
|
||||||
|
[`${prefixCls}-nav-container`]: 1,
|
||||||
|
[`${prefixCls}-nav-container-scrolling`]: showNextPrev,
|
||||||
|
}}
|
||||||
|
key='container'
|
||||||
|
ref='container'
|
||||||
|
>
|
||||||
|
{prevButton}
|
||||||
|
{nextButton}
|
||||||
|
<div class={`${prefixCls}-nav-wrap`} ref='navWrap'>
|
||||||
|
<div class={`${prefixCls}-nav-scroll`}>
|
||||||
|
<div class={navClasses} ref='nav'>
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,4 +1,25 @@
|
||||||
export default {
|
export default {
|
||||||
|
props: {
|
||||||
|
prefixCls: {
|
||||||
|
default: 'ant-tabs',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
tabBarPosition: {
|
||||||
|
default: 'top',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
disabled: Boolean,
|
||||||
|
onKeyDown: {
|
||||||
|
default: () => {},
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
onTabClick: {
|
||||||
|
default: () => {},
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
activeKey: String,
|
||||||
|
panels: Array,
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getTabs () {
|
getTabs () {
|
||||||
const { panels: children, activeKey, prefixCls } = this
|
const { panels: children, activeKey, prefixCls } = this
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Icon from '../icon'
|
||||||
import KeyCode from './KeyCode'
|
import KeyCode from './KeyCode'
|
||||||
import TabBar from './TabBar'
|
import TabBar from './TabBar'
|
||||||
import TabContent from './TabContent'
|
import TabContent from './TabContent'
|
||||||
|
import ScrollableInkTabBar from './ScrollableInkTabBar'
|
||||||
function getDefaultActiveKey (t) {
|
function getDefaultActiveKey (t) {
|
||||||
let activeKey
|
let activeKey
|
||||||
t.$slot.default.forEach((child) => {
|
t.$slot.default.forEach((child) => {
|
||||||
|
@ -34,6 +35,11 @@ export default {
|
||||||
return ['top', 'bottom', 'left', 'right'].includes(value)
|
return ['top', 'bottom', 'left', 'right'].includes(value)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
renderTabBar: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
tabBarProps: Object,
|
||||||
destroyInactiveTabPane: Boolean,
|
destroyInactiveTabPane: Boolean,
|
||||||
activeKey: String,
|
activeKey: String,
|
||||||
defaultActiveKey: String,
|
defaultActiveKey: String,
|
||||||
|
@ -162,6 +168,7 @@ export default {
|
||||||
}
|
}
|
||||||
const tabBarProps = {
|
const tabBarProps = {
|
||||||
props: {
|
props: {
|
||||||
|
...tabBarProps,
|
||||||
panels: panels,
|
panels: panels,
|
||||||
prefixCls: prefixCls,
|
prefixCls: prefixCls,
|
||||||
onKeyDown: onNavKeyDown,
|
onKeyDown: onNavKeyDown,
|
||||||
|
@ -172,9 +179,9 @@ export default {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const contents = [
|
const contents = [
|
||||||
<TabBar {...tabBarProps}>
|
<ScrollableInkTabBar {...tabBarProps}>
|
||||||
{this.$slots.tabBarExtraContent}
|
{this.$slots.tabBarExtraContent}
|
||||||
</TabBar>,
|
</ScrollableInkTabBar>,
|
||||||
<TabContent {...tabContentProps}>
|
<TabContent {...tabContentProps}>
|
||||||
{$slots.default}
|
{$slots.default}
|
||||||
</TabContent>,
|
</TabContent>,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Tabs from './Tabs'
|
import Tabs from './index.vue'
|
||||||
import TabPane from './TabPane'
|
import TabPane from './TabPane'
|
||||||
// import TabContent from './TabContent'
|
import TabContent from './TabContent'
|
||||||
Tabs.TabPane = TabPane
|
Tabs.TabPane = TabPane
|
||||||
export default Tabs
|
export default Tabs
|
||||||
export { TabPane }
|
export { TabPane, TabContent }
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
<script>
|
||||||
|
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'
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
prefixCls: { type: String, default: 'ant-tabs' },
|
||||||
|
activeKey: String,
|
||||||
|
defaultActiveKey: String,
|
||||||
|
hideAdd: { type: Boolean, default: false },
|
||||||
|
onChange: { type: Function, default: () => {} },
|
||||||
|
onTabClick: { type: Function, default: () => {} },
|
||||||
|
onPrevClick: { type: Function, default: () => {} },
|
||||||
|
onNextClick: { type: Function, default: () => {} },
|
||||||
|
tabBarStyle: Object,
|
||||||
|
type: {
|
||||||
|
validator (value) {
|
||||||
|
return ['line', 'card', 'editable-card'].includes(value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tabPosition: {
|
||||||
|
validator (value) {
|
||||||
|
return ['top', 'right', 'bottom', 'left'].includes(value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onEdit: { type: Function, default: () => {} },
|
||||||
|
size: {
|
||||||
|
validator (value) {
|
||||||
|
return ['default', 'small'].includes(value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animated: Boolean | Object,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
createNewTab (targetKey) {
|
||||||
|
const onEdit = this.$props.onEdit
|
||||||
|
if (onEdit) {
|
||||||
|
onEdit(targetKey, 'add')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeTab (targetKey, e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
if (!targetKey) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const onEdit = this.$props.onEdit
|
||||||
|
if (onEdit) {
|
||||||
|
onEdit(targetKey, 'remove')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChange (activeKey) {
|
||||||
|
const onChange = this.$props.onChange
|
||||||
|
if (onChange) {
|
||||||
|
onChange(activeKey)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
const NO_FLEX = ' no-flex'
|
||||||
|
const tabNode = this.$el
|
||||||
|
if (tabNode && !isFlexSupported() && tabNode.className.indexOf(NO_FLEX) === -1) {
|
||||||
|
tabNode.className += NO_FLEX
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
size,
|
||||||
|
type = 'line',
|
||||||
|
tabPosition,
|
||||||
|
children,
|
||||||
|
tabBarStyle,
|
||||||
|
// hideAdd,
|
||||||
|
onTabClick,
|
||||||
|
onPrevClick,
|
||||||
|
onNextClick,
|
||||||
|
animated = true,
|
||||||
|
} = this.$props
|
||||||
|
let { tabBarExtraContent } = this.$props
|
||||||
|
let { inkBarAnimated, tabPaneAnimated } = typeof animated === 'object' ? { // eslint-disable-line
|
||||||
|
inkBarAnimated: animated.inkBar, tabPaneAnimated: animated.tabPane,
|
||||||
|
} : {
|
||||||
|
inkBarAnimated: animated, tabPaneAnimated: animated,
|
||||||
|
}
|
||||||
|
|
||||||
|
// card tabs should not have animation
|
||||||
|
if (type !== 'line') {
|
||||||
|
tabPaneAnimated = 'animated' in this.$props ? tabPaneAnimated : false
|
||||||
|
}
|
||||||
|
const cls = {
|
||||||
|
[`${prefixCls}-mini`]: size === 'small' || size,
|
||||||
|
[`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right',
|
||||||
|
[`${prefixCls}-card`]: type.indexOf('card') >= 0,
|
||||||
|
[`${prefixCls}-${type}`]: true,
|
||||||
|
[`${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 = {
|
||||||
|
inkBarAnimated,
|
||||||
|
extraContent: tabBarExtraContent,
|
||||||
|
onTabClick,
|
||||||
|
onPrevClick,
|
||||||
|
onNextClick,
|
||||||
|
style: tabBarStyle,
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
{...this.$props}
|
||||||
|
class={cls}
|
||||||
|
tabBarPosition={tabPosition}
|
||||||
|
renderTabBar={renderTabBar}
|
||||||
|
// renderTabContent={() => <TabContent animated={tabPaneAnimated} animatedWithMargin />}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
tabBarProps={tabBarProps}
|
||||||
|
>
|
||||||
|
{childrenWithClose || this.$slots.default}
|
||||||
|
</Tabs>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -74,6 +74,8 @@
|
||||||
"webpack-dev-server": "^2.8.2"
|
"webpack-dev-server": "^2.8.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint-plugin-vue": "^3.13.0"
|
"add-dom-event-listener": "^1.0.2",
|
||||||
|
"eslint-plugin-vue": "^3.13.0",
|
||||||
|
"lodash.debounce": "^4.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue