78 lines
1.8 KiB
Vue
78 lines
1.8 KiB
Vue
<template>
|
|
<view
|
|
class="scroll-container"
|
|
@touchstart="handleTouchStart"
|
|
@touchmove="handleTouchMove"
|
|
@touchend="handleTouchEnd"
|
|
:style="{ transform: `translateY(${offsetY}px)` }"
|
|
>
|
|
<slot></slot>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'ScrollContainer',
|
|
data() {
|
|
return {
|
|
startY: 0,
|
|
offsetY: 0,
|
|
isScrolling: false,
|
|
canScroll: true // 控制是否允许滑动
|
|
};
|
|
},
|
|
methods: {
|
|
handleTouchStart(e) {
|
|
// 检查触摸点是否在可滑动区域(页面顶部或底部)
|
|
const touchY = e.touches[0].clientY;
|
|
const windowHeight = uni.getSystemInfoSync().windowHeight;
|
|
|
|
// 只在页面顶部100px或底部100px区域内允许滑动
|
|
this.canScroll = touchY < 100 || touchY > windowHeight - 100;
|
|
|
|
if (this.canScroll) {
|
|
this.startY = e.touches[0].clientY;
|
|
this.isScrolling = true;
|
|
}
|
|
},
|
|
handleTouchMove(e) {
|
|
if (!this.isScrolling || !this.canScroll) return;
|
|
|
|
const currentY = e.touches[0].clientY;
|
|
const deltaY = currentY - this.startY;
|
|
const maxScroll = 100;
|
|
|
|
// 应用阻力效果
|
|
this.offsetY += deltaY * 0.5;
|
|
|
|
// 限制滚动范围
|
|
if (Math.abs(this.offsetY) > maxScroll) {
|
|
this.offsetY = this.offsetY > 0 ? maxScroll : -maxScroll;
|
|
}
|
|
|
|
this.startY = currentY;
|
|
|
|
// 阻止默认行为,避免与内部滚动冲突
|
|
e.preventDefault();
|
|
},
|
|
handleTouchEnd() {
|
|
this.isScrolling = false;
|
|
this.canScroll = true;
|
|
// 使用动画回弹
|
|
this.offsetY = 0;
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.scroll-container {
|
|
width: 100%;
|
|
height: 100vh;
|
|
overflow: hidden;
|
|
transition: transform 0.3s ease-out;
|
|
position: relative;
|
|
/* 允许穿透点击 */
|
|
pointer-events: auto;
|
|
}
|
|
</style> |