提交 840a290d 编写于 作者: d-u-a's avatar d-u-a

update: app-vue + h5 <scroll-view> 支持自定义下拉刷新

上级 7d9ec54a
...@@ -8,6 +8,48 @@ ...@@ -8,6 +8,48 @@
:style="{'overflow-x': scrollX?'auto':'hidden','overflow-y': scrollY?'auto':'hidden'}" :style="{'overflow-x': scrollX?'auto':'hidden','overflow-y': scrollY?'auto':'hidden'}"
class="uni-scroll-view"> class="uni-scroll-view">
<div ref="content"> <div ref="content">
<div
v-if="refresherEnabled"
ref="refresherinner"
:style="{'background-color': refresherBackground, 'height': refresherHeight + 'px'}"
class="uni-scroll-view-refresher">
<div
v-if="refresherDefaultStyle !== 'none'"
class="uni-scroll-view-refresh">
<div class="uni-scroll-view-refresh-inner">
<svg
v-if="refreshState=='pulling'"
:style="{'transform': 'rotate('+ refreshRotate +'deg)'}"
fill="#2BD009"
class="uni-scroll-view-refresh__icon"
width="24"
height="24"
viewBox="0 0 24 24">
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" />
<path
d="M0 0h24v24H0z"
fill="none" />
</svg>
<svg
v-if="refreshState=='refreshing'"
class="uni-scroll-view-refresh__spinner"
width="24"
height="24"
viewBox="25 25 50 50">
<circle
cx="50"
cy="50"
r="20"
fill="none"
style="color: #2BD009;"
stroke-width="3"/>
</svg>
</div>
</div>
<slot
v-if="refresherDefaultStyle=='none'"
name="refresher"/>
</div>
<slot/> <slot/>
</div> </div>
</div> </div>
...@@ -24,6 +66,10 @@ import { ...@@ -24,6 +66,10 @@ import {
const passiveOptions = supportsPassive ? { const passiveOptions = supportsPassive ? {
passive: true passive: true
} : false } : false
// const PULLING = 'pulling'
// const REFRESHING = 'refreshing'
export default { export default {
name: 'ScrollView', name: 'ScrollView',
mixins: [scroller], mixins: [scroller],
...@@ -63,6 +109,26 @@ export default { ...@@ -63,6 +109,26 @@ export default {
enableBackToTop: { enableBackToTop: {
type: [Boolean, String], type: [Boolean, String],
default: false 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 () { data () {
...@@ -70,7 +136,10 @@ export default { ...@@ -70,7 +136,10 @@ export default {
lastScrollTop: this.scrollTopNumber, lastScrollTop: this.scrollTopNumber,
lastScrollLeft: this.scrollLeftNumber, lastScrollLeft: this.scrollLeftNumber,
lastScrollToUpperTime: 0, lastScrollToUpperTime: 0,
lastScrollToLowerTime: 0 lastScrollToLowerTime: 0,
refresherHeight: 0,
refreshRotate: 0,
refreshState: 'pulling'
} }
}, },
computed: { computed: {
...@@ -98,6 +167,14 @@ export default { ...@@ -98,6 +167,14 @@ export default {
}, },
scrollIntoView (val) { scrollIntoView (val) {
this._scrollIntoViewChanged(val) this._scrollIntoViewChanged(val)
},
refresherTriggered (val) {
// TODO
if (val === true) {
this._setRefreshState('refreshing')
} else if (val === false) {
this._setRefreshState('restore')
}
} }
}, },
mounted () { mounted () {
...@@ -151,6 +228,23 @@ export default { ...@@ -151,6 +228,23 @@ export default {
if (needStop) { if (needStop) {
event.stopPropagation() 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) { this.__handleTouchStart = function (event) {
...@@ -163,12 +257,22 @@ export default { ...@@ -163,12 +257,22 @@ export default {
x: event.touches[0].pageX, x: event.touches[0].pageX,
y: event.touches[0].pageY y: event.touches[0].pageY
} }
if (self.refresherEnabled && self.refreshState !== 'refreshing' && self.$refs.main.scrollTop === 0) {
self.refreshState = 'pulling'
}
} }
} }
this.__handleTouchEnd = function (event) { this.__handleTouchEnd = function (event) {
touchStart = null
disableScrollBounce({ disableScrollBounce({
disable: false 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('touchstart', this.__handleTouchStart, passiveOptions)
this.$refs.main.addEventListener('touchmove', this.__handleTouchMove, passiveOptions) this.$refs.main.addEventListener('touchmove', this.__handleTouchMove, passiveOptions)
...@@ -374,6 +478,19 @@ export default { ...@@ -374,6 +478,19 @@ export default {
this.$refs.content.removeEventListener('transitionend', this.__transitionEnd) this.$refs.content.removeEventListener('transitionend', this.__transitionEnd)
this.$refs.content.removeEventListener('webkitTransitionEnd', 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 () { getScrollPosition () {
const main = this.$refs.main const main = this.$refs.main
return { return {
...@@ -402,4 +519,71 @@ uni-scroll-view[hidden] { ...@@ -402,4 +519,71 @@ uni-scroll-view[hidden] {
height: 100%; height: 100%;
max-height: inherit; 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;
}
}
</style> </style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册