mrr.sj.front/components/scroll-container/scroll-container.vue

78 lines
1.8 KiB
Vue
Raw Normal View History

2026-03-24 11:45:13 +08:00
<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>