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.
230 lines
6.1 KiB
230 lines
6.1 KiB
function processDeltaY (evt, identifier, startY) {
|
|
const touch = Array.prototype.slice.call(evt.changedTouches).filter(touch => touch.identifier === identifier)[0]
|
|
if (!touch) {
|
|
return false
|
|
}
|
|
evt.deltaY = touch.pageY - startY
|
|
return true
|
|
}
|
|
|
|
// const ratio = 2.2
|
|
|
|
const PULLING = 'pulling'
|
|
const REACHED = 'reached'
|
|
|
|
const ABORTING = 'aborting'
|
|
const REFRESHING = 'refreshing'
|
|
const RESTORING = 'restoring'
|
|
|
|
export default {
|
|
mounted () {
|
|
if (this.enablePullDownRefresh) {
|
|
this.refreshContainerElem = this.$refs.refresh.$el
|
|
this.refreshControllerElem = this.refreshContainerElem.querySelector('.uni-page-refresh')
|
|
this.refreshInnerElemStyle = this.refreshControllerElem.querySelector('.uni-page-refresh-inner').style
|
|
|
|
UniServiceJSBridge.on(this.$route.params.__id__ + '.startPullDownRefresh', () => {
|
|
if (!this.state) {
|
|
this.state = REFRESHING
|
|
this._addClass()
|
|
setTimeout(() => {
|
|
this._refreshing()
|
|
}, 50)
|
|
}
|
|
})
|
|
|
|
UniServiceJSBridge.on(this.$route.params.__id__ + '.stopPullDownRefresh', () => {
|
|
if (this.state === REFRESHING) {
|
|
this._removeClass()
|
|
this.state = RESTORING
|
|
this._addClass()
|
|
|
|
this._restoring(() => {
|
|
this._removeClass()
|
|
this.state = this.distance = this.offset = null
|
|
})
|
|
}
|
|
})
|
|
}
|
|
},
|
|
methods: {
|
|
_touchstart (evt) {
|
|
const touch = evt.changedTouches[0]
|
|
this.touchId = touch.identifier
|
|
this.startY = touch.pageY
|
|
if ([ABORTING, REFRESHING, RESTORING].indexOf(this.state) >= 0) {
|
|
this.canRefresh = false
|
|
} else {
|
|
this.canRefresh = true
|
|
}
|
|
},
|
|
_touchmove (evt) {
|
|
if (!this.canRefresh) {
|
|
return
|
|
}
|
|
if (!processDeltaY(evt, this.touchId, this.startY)) {
|
|
return
|
|
}
|
|
|
|
let {
|
|
deltaY
|
|
} = evt
|
|
|
|
if ((document.documentElement.scrollTop || document.body.scrollTop) !== 0) {
|
|
this.touchId = null
|
|
return
|
|
}
|
|
|
|
if (deltaY < 0 && !this.state) {
|
|
return
|
|
}
|
|
|
|
evt.preventDefault()
|
|
|
|
if (this.distance == null) {
|
|
this.offset = deltaY
|
|
this.state = PULLING
|
|
this._addClass()
|
|
}
|
|
|
|
deltaY = deltaY - this.offset
|
|
|
|
if (deltaY < 0) {
|
|
deltaY = 0
|
|
}
|
|
|
|
this.distance = deltaY
|
|
|
|
const reached = deltaY >= this.refreshOptions.range && this.state !== REACHED
|
|
const pulling = deltaY < this.refreshOptions.range && this.state !== PULLING
|
|
|
|
if (reached || pulling) {
|
|
this._removeClass()
|
|
this.state = this.state === REACHED ? PULLING : REACHED
|
|
this._addClass()
|
|
}
|
|
|
|
this._pulling(deltaY)
|
|
},
|
|
_touchend (evt) {
|
|
if (!processDeltaY(evt, this.touchId, this.startY)) {
|
|
return
|
|
}
|
|
if (this.state === null) {
|
|
return
|
|
}
|
|
if (this.state === PULLING) {
|
|
this._removeClass()
|
|
this.state = ABORTING
|
|
this._addClass()
|
|
this._aborting(() => {
|
|
this._removeClass()
|
|
this.state = this.distance = this.offset = null
|
|
})
|
|
} else if (this.state === REACHED) {
|
|
this._removeClass()
|
|
this.state = REFRESHING
|
|
this._addClass()
|
|
this._refreshing()
|
|
}
|
|
},
|
|
_toggleClass (type) {
|
|
if (!this.state) {
|
|
return
|
|
}
|
|
const elem = this.refreshContainerElem
|
|
if (elem) {
|
|
elem.classList[type]('uni-page-refresh--' + this.state)
|
|
}
|
|
},
|
|
_addClass () {
|
|
this._toggleClass('add')
|
|
},
|
|
_removeClass () {
|
|
this._toggleClass('remove')
|
|
},
|
|
_pulling (deltaY) {
|
|
const elem = this.refreshControllerElem
|
|
if (!elem) {
|
|
return
|
|
}
|
|
|
|
const style = elem.style
|
|
|
|
let rotate = deltaY / this.refreshOptions.range
|
|
|
|
if (rotate > 1) {
|
|
rotate = 1
|
|
} else {
|
|
rotate = rotate * rotate * rotate
|
|
}
|
|
|
|
const y = Math.round(deltaY / (this.refreshOptions.range / this.refreshOptions.height))
|
|
|
|
const transform = y ? 'translate3d(-50%, ' + y + 'px, 0)' : 0
|
|
|
|
style.webkitTransform = transform
|
|
style.clip = 'rect(' + (45 - y) + 'px,45px,45px,-5px)'
|
|
|
|
this.refreshInnerElemStyle.webkitTransform = 'rotate(' + 360 * rotate + 'deg)'
|
|
},
|
|
_aborting (callback) {
|
|
const elem = this.refreshControllerElem
|
|
if (!elem) {
|
|
return
|
|
}
|
|
|
|
const style = elem.style
|
|
|
|
if (style.webkitTransform) {
|
|
style.webkitTransition = '-webkit-transform 0.3s'
|
|
style.webkitTransform = 'translate3d(-50%, 0, 0)'
|
|
const abortTransitionEnd = function () {
|
|
timeout && clearTimeout(timeout)
|
|
elem.removeEventListener('webkitTransitionEnd', abortTransitionEnd)
|
|
style.webkitTransition = ''
|
|
callback()
|
|
}
|
|
elem.addEventListener('webkitTransitionEnd', abortTransitionEnd)
|
|
const timeout = setTimeout(abortTransitionEnd, 350) // 部分手机,部分情况webkitTransitionEnd不触发
|
|
} else {
|
|
callback()
|
|
}
|
|
},
|
|
_refreshing () {
|
|
const elem = this.refreshControllerElem
|
|
if (!elem) {
|
|
return
|
|
}
|
|
|
|
const style = elem.style
|
|
style.webkitTransition = '-webkit-transform 0.2s'
|
|
style.webkitTransform = 'translate3d(-50%, ' + this.refreshOptions.height + 'px, 0)'
|
|
|
|
// Service 执行 refresh
|
|
UniServiceJSBridge.emit('onPullDownRefresh', {}, this.$route.params.__id__)
|
|
},
|
|
_restoring (callback) {
|
|
const elem = this.refreshControllerElem
|
|
if (!elem) {
|
|
return
|
|
}
|
|
|
|
const style = elem.style
|
|
|
|
style.webkitTransition = '-webkit-transform 0.3s'
|
|
style.webkitTransform += ' scale(0.01)'
|
|
|
|
const restoreTransitionEnd = function () {
|
|
timeout && clearTimeout(timeout)
|
|
elem.removeEventListener('webkitTransitionEnd', restoreTransitionEnd)
|
|
style.webkitTransition = ''
|
|
style.webkitTransform = 'translate3d(-50%, 0, 0)'
|
|
callback()
|
|
}
|
|
|
|
elem.addEventListener('webkitTransitionEnd', restoreTransitionEnd)
|
|
const timeout = setTimeout(restoreTransitionEnd, 350) // 部分手机,部分情况webkitTransitionEnd不触发
|
|
}
|
|
}
|
|
}
|
|
|