const Binding = uni.requireNativePlugin('bindingx') const animation = uni.requireNativePlugin('animation') const dom = uni.requireNativePlugin('dom') import Util from '../../js_sdk/util.js' export default { data () { return { disableTouch: false, isTouch: false, touchTime: 0, interval: false, loadingType: '', direction: '' } }, beforeDestroy () { if ( this.flipBinding ) { Binding.unbind({ token: this.flipBinding.token, eventType: 'pan' }) this.sliderBinding = null } this.resetFlipAnimationBinding() }, methods: { fliptouchstart (event) { if ( this.isTouch || this.disableTouch ) { return } this.isTouch = true this.touchTime = 0 this.interval = true this.setInterval() let touch = event.touches[0] this.startX = touch.pageX this.startY = touch.pageY }, fliptouchmove (event) { if ( this.isTouch && !this.disableTouch ) { let touch = event.touches[0] let offset = this.vertical ? touch.pageY - this.startY : touch.pageX - this.startX if ( !this.direction ) { if ( Math.abs(offset) < this.sliderFault ) return if ( offset < 0 ) { if ( this.nextIndex < this.count && this.nextIndex != 0 ) { if ( this.type != 'none' ) {this.direction = 'next'} } else if ( this.pullupable && this.loadingState != 'loading' && this.loadingState != 'success' && this.loadingState != 'fail' ) { this.loadingType = 'pullup' this.disableTouch = true this.clearInterval() this.pulling() } } else { if ( this.prevIndex > -1 && this.prevIndex != this.count - 1 ) { if ( this.type != 'none' ) {this.direction = 'prev'} } else if ( this.pulldownable && this.loadingState != 'loading' && this.loadingState != 'success' && this.loadingState != 'fail' ) { this.loadingType = 'pulldown' this.disableTouch = true this.clearInterval() this.pulling() } } } if ( this.direction ) { this.disableTouch = true this.flipTouchAction() } else { this.resetPageBinding() } } }, async fliptouchend (e) { if ( this.isTouch && !this.disableTouch ) { let rect = await this.getRect(this.$refs.yingbingFlip) let size = this.vertical ? rect.height : rect.width this.clearInterval() let start = this.vertical ? this.startY : this.startX if ( this.touchTime <= 200 && (!this.unableClickPage || this.type == 'none') ) { if (start > (size / 4) * 3 && this.nextIndex < this.count && this.nextIndex != 0 ) { this.flipToNextBindingX() } else if (start < (size / 4) && this.prevIndex >= 0 && this.prevIndex != this.count - 1 ) { this.flipToPrevBindingX() } else { this.resetPageBinding() } } else { this.resetPageBinding() } } }, async flipTouchAction () { let props = [] let rect = await this.getRect(this.$refs.yingbingFlip) let size = this.vertical ? rect.height : rect.width let translate = this.translate let shadowProperty = this.vertical ? 'height' : 'width' let key = this.vertical ? 'y' : 'x' if ( this.direction == 'prev' ) { if ( this.prevIndex > -1 ) { props.push({ element: this.getEl('yingbingFlipItem_' + this.prevIndex), property: 'transform.' + translate, expression: `${key} < 0 ? ${-size} : (${key} > ${size} ? 0 : ${key}-${size})` }) if ( this.type == 'real' ) { props.push({ element: this.getEl('yingbingFlipItemContent_' + this.prevIndex), property: 'transform.' + translate, expression: `${key} < 0 ? ${size} : (${key} > ${size} ? 0 : ${size}-${key})` }) props.push({ element: this.getEl('yingbingFlipItemBg_' + this.prevIndex), property: 'transform.' + translate, expression: `${key} < 0 ? 0 : (${key} > ${size} ? ${size} : ${key} + 0)` }) props.push({ element: this.getEl('yingbingFlipItemShadow_' + this.prevIndex), property: shadowProperty, expression: `${size} / 2 - abs(${key}) / 2'` }) } } } else { if ( this.nextIndex < this.count ) { props.push({ element: this.getEl('yingbingFlipItem_' + this.nextIndex), property: 'transform.' + translate, expression: '0+0' }) } props.push({ element: this.getEl('yingbingFlipItem_' + this.currentIndex), property: 'transform.' + translate, expression: `${key} > 0 ? 0 : (${key} < ${-size} ? ${-size} : ${key} + 0)` }) if ( this.type == 'real' ) { props.push({ element: this.getEl('yingbingFlipItemContent_' + this.currentIndex), property: 'transform.' + translate, expression: `${key} > 0 ? 0 : (${key} < ${-size} ? ${size} : 0 - ${key})'` }) props.push({ element: this.getEl('yingbingFlipItemBg_' + this.currentIndex), property: 'transform.' + translate, expression: `${key} > 0 ? ${size} : (${key} < ${-size} ? 0 : ${key}+${size})` }) props.push({ element: this.getEl('yingbingFlipItemShadow_' + this.currentIndex), property: shadowProperty, expression: `abs(${key})/2+0` }) } } this.flipBinding = Binding.bind({ anchor: this.getEl('yingbingFlip'), eventType: 'pan', props: props }, (e) => { if ((e.state == 'end' || e.state == 'cancel') && this.flipBinding) { this.clearInterval() Binding.unbind({ token: this.flipBinding.token, eventType: 'pan' }) this.flipBinding = null let value = this.direction == 'next' ? 1 : -1; if (this.touchTime <= 200) { this.pageAnimation(-value * size, size); } else { let index = this.direction == 'next' ? this.currentIndex : this.prevIndex let deltaX = Binding.getComputedStyle(this.getEl('yingbingFlipItem_' + index))[translate] let offset = this.direction == 'next' ? Math.abs(deltaX) : size - Math.abs(deltaX) if ( offset >= size / 4) { this.pageAnimation(-value * size, size) } else { this.pageAnimation(0, size); } } } }) }, flipToNextBindingX () { if ( !this.disableTouch && this.nextIndex < this.count && (this.nextIndex != 0 || this.circular) ) { this.direction = 'next' this.flipToBindingX() } }, flipToPrevBindingX () { if ( !this.disableTouch && this.prevIndex >= 0 && (this.prevIndex != this.count - 1 || this.circular) ) { this.direction = 'prev' this.flipToBindingX() } }, async flipToBindingX () { this.disableTouch = true let value = this.direction == 'next' ? 1 : -1; let rect = await this.getRect(this.$refs.yingbingFlip) let size = this.vertical ? rect.height : rect.width this.pageAnimation(-value * size, size) }, getRect (el) { return new Promise(resolve => { dom.getComponentRect(el, res => { resolve(res.size) }) }) }, setInterval () { this.touchTimer = setTimeout(() => { this.touchTime += 10 if ( this.interval ) { this.setInterval() } }, 10) }, clearInterval () { this.interval = false if ( this.touchTimer ) { clearTimeout(this.touchTimer) this.touchTimer = null } }, pageAnimation (offset, size) { let duration = this.type == 'none' ? 0.1 : this.duration let late = offset let translate = this.translate let shadowProperty = this.vertical ? 'height' : 'width' let props = [] if ( this.direction == 'prev' ) { if ( this.prevIndex > -1 ) { let itemTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItem_' + this.prevIndex))[translate] props.push({ element: this.getEl('yingbingFlipItem_' + this.prevIndex), property: 'transform.' + translate, expression: `linear(t, ${itemTrans}, ${late - size - itemTrans}, ${duration})` }) if ( this.type == 'real' ) { let contentTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemContent_' + this.prevIndex))[translate] props.push({ element: this.getEl('yingbingFlipItemContent_' + this.prevIndex), property: 'transform.' + translate, expression: `linear(t, ${contentTrans}, ${-(late - size) - contentTrans}, ${duration})` }) let bgTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemBg_' + this.prevIndex))[translate] props.push({ element: this.getEl('yingbingFlipItemBg_' + this.prevIndex), property: 'transform.' + translate, expression: `linear(t, ${bgTrans}, ${late - bgTrans}, ${duration})` }) let shadowSize = Binding.getComputedStyle(this.getEl('yingbingFlipItemShadow_' + this.prevIndex))[shadowProperty] || size props.push({ element: this.getEl('yingbingFlipItemShadow_' + this.prevIndex), property: shadowProperty, expression: `linear(t, ${shadowSize}, ${-(late - size) - shadowSize}, ${duration})` }) } this.flipAnimationBinding = Binding.bind({ eventType: 'timing', exitExpression: 't>' + duration, props: props }, (e) => { if (e.state == 'exit' && this.flipAnimationBinding && e.t > duration) { Binding.unbind({ token: this.flipAnimationBinding.token, eventType: 'timing' }) this.flipAnimationBinding = null if ( Math.abs(offset) > 0 ) { this.handleFlipChange(this.direction == 'next' ? 1 : -1) this.$nextTick(function () { this.resetPageBinding() }) } else { this.resetPageBinding(); } } }) } } else { if ( this.nextIndex < this.count ) { animation.transition(this.getRef('yingbingFlipItem_' + this.nextIndex), { styles: { transform: `${translate}(0)` }, duration: 0, timingFunction: 'linear', needLayout: true }) } animation.transition(this.getRef('yingbingFlipItem_' + this.currentIndex), { styles: { transform: `${translate}(${late}px)` }, duration: duration, timingFunction: 'linear', needLayout: true }, () => { if ( Math.abs(offset) > 0 ) { this.handleFlipChange(this.direction == 'next' ? 1 : -1) this.$nextTick(function () { this.resetPageBinding() }) } else { this.resetPageBinding(); } }) if ( this.type == 'real' ) { animation.transition(this.getRef('yingbingFlipItemContent_' + this.currentIndex), { styles: { transform: `${translate}(${-late}px)` }, duration: duration, timingFunction: 'linear', needLayout: true }) animation.transition(this.getRef('yingbingFlipItemBg_' + this.currentIndex), { styles: { transform: `${translate}(${size + late}px)` }, duration: duration, timingFunction: 'linear', needLayout: true }) let styles = {} styles[shadowProperty] = -late + 'px' animation.transition(this.getRef('yingbingFlipItemShadow_' + this.currentIndex), { styles: styles, duration: duration, timingFunction: 'linear', needLayout: true }) } // if ( this.nextIndex < this.count ) { // props.push({ // element: this.getEl('yingbingFlipItem_' + this.nextIndex), // property: 'transform.' + translate, // expression: '0+0' // }) // } // let itemTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItem_' + this.currentIndex))[translate] // props.push({ // element: this.getEl('yingbingFlipItem_' + this.currentIndex), // property: 'transform.' + translate, // expression: `linear(t, ${itemTrans}, ${late - itemTrans}, ${duration})` // }) // if ( this.type == 'real' ) { // let contentTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemContent_' + this.currentIndex))[translate] // props.push({ // element: this.getEl('yingbingFlipItemContent_' + this.currentIndex), // property: 'transform.' + translate, // expression: `linear(t, ${contentTrans}, ${-late - contentTrans}, ${duration})` // }) // let bgTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemBg_' + this.currentIndex))[translate] // props.push({ // element: this.getEl('yingbingFlipItemBg_' + this.currentIndex), // property: 'transform.' + translate, // expression: `linear(t, ${bgTrans}, ${size + late - bgTrans}, ${duration})` // }) // let shadowSize = Binding.getComputedStyle(this.getEl('yingbingFlipItemShadow_' + this.currentIndex))[shadowProperty] // props.push({ // element: this.getEl('yingbingFlipItemShadow_' + this.currentIndex), // property: shadowProperty, // expression: `linear(t, ${shadowSize}, ${-late - shadowSize}, ${duration})` // }) // } } }, pulling () { let loadingType = this.loadingType let size = loadingType == 'pullup' ? this.pullupHeight : this.pulldownHeight let key = this.vertical ? 'y' : 'x' let translate = this.translate let props = [ { element: this.getEl('yingbing_flip_' + loadingType), property: 'transform.' + translate, expression: loadingType == 'pullup' ? `abs(${key}) > ${size} ? 0 : ${key} + ${size}` : `abs(${key}) > ${size} ? 0 : ${key} - ${size}` }, { element: this.getEl('yingbing_flip_' + loadingType + '_default'), property: 'opacity', expression: `abs(${key}) < ${size} ? 1 : 0` }, { element: this.getEl('yingbing_flip_' + loadingType + '_ready'), property: 'opacity', expression: `abs(${key}) < ${size} ? 0 : 1` }, { element: this.getEl('yingbing_flip_' + loadingType + '_loading'), property: 'opacity', expression: '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_success'), property: 'opacity', expression: '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_fail'), property: 'opacity', expression: '0+0' } ] this.flipBinding = Binding.bind({ anchor: this.getEl('yingbingFlip'), eventType: 'pan', props: props }, (e) => { if ((e.state == 'end' || e.state == 'cancel') && this.flipBinding) { Binding.unbind({ token: this.flipBinding.token, eventType: 'pan' }) this.flipBinding = null let deltaX = Binding.getComputedStyle(this.getEl('yingbing_flip_' + loadingType))[translate] if ( deltaX == 0 ) { this.loadingState = 'ready' this.pullingRefreshBindingx() } else { this.loadingState = 'default' this.resetPullingBindingx() } } }) }, resetPullingBindingx () { let loadingType = this.loadingType let translate = this.translate let size = loadingType == 'pullup' ? this.pullupHeight : this.pulldownHeight let trans = loadingType == 'pullup' ? size : -size let deltaX = Binding.getComputedStyle(this.getEl('yingbing_flip_' + loadingType))[translate] let duration = 300 let props = [ { element: this.getEl('yingbing_flip_' + loadingType), property: 'transform.' + translate, expression: `linear(t, ${deltaX}, ${trans}, ${duration})` }, { element: this.getEl('yingbing_flip_' + loadingType + '_default'), property: 'opacity', expression: this.loadingState == 'default' ? '1+0' : '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_ready'), property: 'opacity', expression: '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_loading'), property: 'opacity', expression: '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_success'), property: 'opacity', expression: this.loadingState == 'success' ? '1+0' : '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_fail'), property: 'opacity', expression: this.loadingState == 'fail' ? '1+0' : '0+0' } ] this.flipAnimationBinding = Binding.bind({ eventType: 'timing', exitExpression: 't>' + duration, props: props }, (e) => { if (e.state == 'exit' && this.flipAnimationBinding && e.t > duration) { this.resetFlipAnimationBinding() this.loadingState = '' this.resetPageBinding() } }) }, pullingRefreshBindingx () { let loadingType = this.loadingType let duration = 1 let props = [ { element: this.getEl('yingbing_flip_' + loadingType + '_default'), property: 'opacity', expression: '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_ready'), property: 'opacity', expression: '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_loading'), property: 'opacity', expression: '1+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_success'), property: 'opacity', expression: '0+0' }, { element: this.getEl('yingbing_flip_' + loadingType + '_fail'), property: 'opacity', expression: '0+0' } ] this.flipAnimationBinding = Binding.bind({ eventType: 'timing', exitExpression: 't>' + duration, props: props }, (e) => { if (e.state == 'exit' && this.flipAnimationBinding && e.t > duration) { this.resetFlipAnimationBinding() this.pullingRefresh(loadingType) } }) }, resetFlipAnimationBinding () { if ( this.flipAnimationBinding ) { Binding.unbind({ token: this.flipAnimationBinding.token, eventType: 'timing' }) this.flipAnimationBinding = null } }, getEl (selector) { return this.$refs[selector] ? Util.getEl(this.$refs[selector].length > 0 ? this.$refs[selector][0] : this.$refs[selector]) : null }, getRef (selector) { return this.$refs[selector] ? this.$refs[selector].length > 0 ? this.$refs[selector][0] : this.$refs[selector] : null }, resetPageBinding () { this.direction = '' this.touchTime = 0 this.startX = 0 this.startY = 0 this.$nextTick(function () { this.isTouch = false this.disableTouch = false }) } } }