diff --git a/src/core/view/components/scroll-view/index.vue b/src/core/view/components/scroll-view/index.vue
index 30314f8c895284dbecc0477dc96193e792ac6026..45e60700e2770333d3efa11598f3dfe63b4603ca 100644
--- a/src/core/view/components/scroll-view/index.vue
+++ b/src/core/view/components/scroll-view/index.vue
@@ -8,6 +8,48 @@
:style="{'overflow-x': scrollX?'auto':'hidden','overflow-y': scrollY?'auto':'hidden'}"
class="uni-scroll-view">
@@ -24,6 +66,10 @@ import {
const passiveOptions = supportsPassive ? {
passive: true
} : false
+
+// const PULLING = 'pulling'
+// const REFRESHING = 'refreshing'
+
export default {
name: 'ScrollView',
mixins: [scroller],
@@ -63,6 +109,26 @@ export default {
enableBackToTop: {
type: [Boolean, String],
default: false
+ },
+ refresherEnabled: {
+ type: [Boolean, String],
+ default: false
+ },
+ refresherThreshold: {
+ type: Number,
+ default: 45
+ },
+ refresherDefaultStyle: {
+ type: String,
+ default: 'back'
+ },
+ refresherBackground: {
+ type: String,
+ default: '#fff'
+ },
+ refresherTriggered: {
+ type: [Boolean, String],
+ default: false
}
},
data () {
@@ -70,7 +136,10 @@ export default {
lastScrollTop: this.scrollTopNumber,
lastScrollLeft: this.scrollLeftNumber,
lastScrollToUpperTime: 0,
- lastScrollToLowerTime: 0
+ lastScrollToLowerTime: 0,
+ refresherHeight: 0,
+ refreshRotate: 0,
+ refreshState: 'pulling'
}
},
computed: {
@@ -98,6 +167,14 @@ export default {
},
scrollIntoView (val) {
this._scrollIntoViewChanged(val)
+ },
+ refresherTriggered (val) {
+ // TODO
+ if (val === true) {
+ this._setRefreshState('refreshing')
+ } else if (val === false) {
+ this._setRefreshState('restore')
+ }
}
},
mounted () {
@@ -151,6 +228,23 @@ export default {
if (needStop) {
event.stopPropagation()
}
+
+ if (self.refresherEnabled && self.refreshState !== 'refreshing' && touchStart && main.scrollTop === 0) {
+ let dy = y - touchStart.y
+ self.refresherHeight = dy
+
+ let rotate = dy / self.refresherThreshold
+ if (rotate > 1) {
+ rotate = 1
+ } else {
+ rotate = rotate * 360
+ }
+ self.refreshRotate = rotate
+
+ self.$trigger('refresherpulling', event, {
+ deltaY: dy
+ })
+ }
}
this.__handleTouchStart = function (event) {
@@ -163,12 +257,22 @@ export default {
x: event.touches[0].pageX,
y: event.touches[0].pageY
}
+ if (self.refresherEnabled && self.refreshState !== 'refreshing' && self.$refs.main.scrollTop === 0) {
+ self.refreshState = 'pulling'
+ }
}
}
this.__handleTouchEnd = function (event) {
+ touchStart = null
disableScrollBounce({
disable: false
})
+ if (self.refresherHeight >= self.refresherThreshold) {
+ self._setRefreshState('refreshing')
+ } else {
+ self.refresherHeight = 0
+ self.$trigger('refresherabort', event, {})
+ }
}
this.$refs.main.addEventListener('touchstart', this.__handleTouchStart, passiveOptions)
this.$refs.main.addEventListener('touchmove', this.__handleTouchMove, passiveOptions)
@@ -374,6 +478,19 @@ export default {
this.$refs.content.removeEventListener('transitionend', this.__transitionEnd)
this.$refs.content.removeEventListener('webkitTransitionEnd', this.__transitionEnd)
},
+ _setRefreshState (state) {
+ switch (state) {
+ case 'refreshing':
+ this.refresherHeight = this.refresherThreshold
+ this.$trigger('refresherrefresh', event, {})
+ break
+ case 'restore':
+ this.refresherHeight = 0
+ this.$trigger('refresherrestore', {}, {})
+ break
+ }
+ this.refreshState = state
+ },
getScrollPosition () {
const main = this.$refs.main
return {
@@ -402,4 +519,71 @@ uni-scroll-view[hidden] {
height: 100%;
max-height: inherit;
}
+
+.uni-scroll-view-refresher {
+ position: relative;
+ overflow: hidden;
+}
+
+.uni-scroll-view-refresh {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+}
+
+.uni-scroll-view-refresh-inner {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 0;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ background-color: #fff;
+ box-shadow: 0 1px 6px rgba(0, 0, 0, .117647), 0 1px 4px rgba(0, 0, 0, .117647);
+}
+
+.uni-scroll-view-refresh__spinner {
+ transform-origin: center center;
+ animation: uni-scroll-view-refresh-rotate 2s linear infinite;
+}
+
+.uni-scroll-view-refresh__spinner > circle {
+ stroke: currentColor;
+ stroke-linecap: round;
+ animation: uni-scroll-view-refresh-dash 2s linear infinite;
+}
+
+@keyframes uni-scroll-view-refresh-rotate {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes uni-scroll-view-refresh-dash {
+ 0% {
+ stroke-dasharray: 1, 200;
+ stroke-dashoffset: 0;
+ }
+
+ 50% {
+ stroke-dasharray: 89, 200;
+ stroke-dashoffset: -35px;
+ }
+
+ 100% {
+ stroke-dasharray: 89, 200;
+ stroke-dashoffset: -124px;
+ }
+}