页面下拉刷新以及底部回弹
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<view
|
||||
ref="sc"
|
||||
class="sc"
|
||||
@touchstart="onStart"
|
||||
@touchmove="onMove"
|
||||
@touchend="onEnd"
|
||||
@touchcancel="onEnd"
|
||||
>
|
||||
<view class="sheet" :class="{ anim: !dragging }" :style="{ transform: 'translate3d(0,' + offset + 'px,0)' }">
|
||||
<view v-if="offset > 8" class="hint">{{ offset > 54 ? '松开刷新' : '下拉刷新' }}</view>
|
||||
<slot />
|
||||
<view class="pad" :class="{ dock }" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FyScroll',
|
||||
props: {
|
||||
dock: { type: Boolean, default: false }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
offset: 0,
|
||||
dragging: false,
|
||||
sy: 0
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const el = this.box()
|
||||
if (el && el.addEventListener) el.addEventListener('wheel', this.onWheel, { passive: false })
|
||||
})
|
||||
},
|
||||
beforeUnmount() {
|
||||
const el = this.box()
|
||||
if (el && el.removeEventListener) el.removeEventListener('wheel', this.onWheel)
|
||||
},
|
||||
methods: {
|
||||
box() {
|
||||
const r = this.$refs.sc
|
||||
if (!r) return this.$el
|
||||
return r.$el || r
|
||||
},
|
||||
atTop(el) {
|
||||
return el.scrollTop <= 0
|
||||
},
|
||||
atBottom(el) {
|
||||
return el.scrollTop + el.clientHeight >= el.scrollHeight - 2
|
||||
},
|
||||
onStart(e) {
|
||||
this.sy = e.touches && e.touches[0] ? e.touches[0].clientY : 0
|
||||
},
|
||||
onMove(e) {
|
||||
const el = this.box()
|
||||
if (!el || el.scrollTop == null) return
|
||||
const y = e.touches && e.touches[0] ? e.touches[0].clientY : this.sy
|
||||
const dy = y - this.sy
|
||||
if (this.atTop(el) && dy > 0) {
|
||||
this.dragging = true
|
||||
this.offset = Math.min(dy * 0.45, 88)
|
||||
if (e.cancelable) e.preventDefault()
|
||||
} else if (this.atBottom(el) && dy < 0) {
|
||||
this.dragging = true
|
||||
this.offset = Math.max(dy * 0.45, -88)
|
||||
if (e.cancelable) e.preventDefault()
|
||||
} else if (this.offset) {
|
||||
this.dragging = false
|
||||
this.offset = 0
|
||||
}
|
||||
},
|
||||
onEnd() {
|
||||
const refresh = this.offset > 54
|
||||
this.dragging = false
|
||||
this.offset = 0
|
||||
if (refresh) this.$emit('refresh')
|
||||
},
|
||||
onWheel(e) {
|
||||
const el = this.box()
|
||||
if (!el) return
|
||||
if (this.atBottom(el) && e.deltaY > 0) {
|
||||
e.preventDefault()
|
||||
this.nudge(Math.max(-72, -Math.min(e.deltaY, 80) * 0.45))
|
||||
} else if (this.atTop(el) && e.deltaY < 0) {
|
||||
e.preventDefault()
|
||||
this.nudge(Math.min(72, Math.min(-e.deltaY, 80) * 0.35))
|
||||
}
|
||||
},
|
||||
nudge(v) {
|
||||
this.dragging = true
|
||||
this.offset = v
|
||||
clearTimeout(this._nudge)
|
||||
this._nudge = setTimeout(() => {
|
||||
const refresh = this.offset > 54
|
||||
this.dragging = false
|
||||
this.offset = 0
|
||||
if (refresh) this.$emit('refresh')
|
||||
}, 70)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sc {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.sc::-webkit-scrollbar { width: 0; height: 0; display: none; }
|
||||
.sheet.anim { transition: transform 0.48s cubic-bezier(0.22, 1.28, 0.36, 1); }
|
||||
.hint {
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
color: #6B7280;
|
||||
padding: 8rpx 0 4rpx;
|
||||
}
|
||||
.pad { height: 32rpx; }
|
||||
.pad.dock { height: calc(128rpx + env(safe-area-inset-bottom)); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user