You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
7.3 KiB
286 lines
7.3 KiB
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 () {
|
|
this.updatedCal()
|
|
},
|
|
|
|
beforeDestroy () {
|
|
if (this.resizeEvent) {
|
|
this.resizeEvent.remove()
|
|
}
|
|
},
|
|
watch: {
|
|
tabBarPosition (val) {
|
|
this.setOffset(0)
|
|
},
|
|
},
|
|
methods: {
|
|
updatedCal () {
|
|
this.setNextPrev()
|
|
this.$nextTick(() => {
|
|
this.scrollToActiveTab()
|
|
})
|
|
},
|
|
setNextPrev () {
|
|
const navNode = this.$refs.nav
|
|
const navNodeWH = this.getOffsetWH(navNode)
|
|
const navWrapNode = this.$refs.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.$refs.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 } = this
|
|
const navWrap = this.$refs.navWrap
|
|
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.$refs.navWrap
|
|
const navWrapNodeWH = this.getOffsetWH(navWrapNode)
|
|
const { offset } = this
|
|
this.setOffset(offset + navWrapNodeWH)
|
|
},
|
|
|
|
nextClick (e) {
|
|
this.$props.onNextClick(e)
|
|
const navWrapNode = this.$refs.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>
|
|
)
|
|
},
|
|
},
|
|
}
|