Uniapp 版
<template>
<view class="bounce" :animation="animationData">
<view class="box" @touchstart="touchstart" @touchend="touchend" @touchmove="touchmove">
<view v-for="i in 20" :key="i">{{ i }}</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
pageY: 0,
animationData: {},
touchmoveY: 0,
};
},
methods: {
getAnimation(s, h) {
let animation = uni.createAnimation({
duration: s,
timingDunction: 'ease',
})
animation.translateY(h).step()
this.animationData = animation.export()
},
touchstart(e) {
this.pageY = e.touches[0].pageY
},
touchend(e) {
this.getAnimation(300, 0)
},
touchmove(e) {
let pageY = Math.ceil(e.touches[0].pageY)
let h = pageY - this.pageY;
if (h < 0 && pageY < this.touchmoveY && pageY >= 200) {
this.getAnimation(300, h / 2 + 'px');
} else {
this.getAnimation(300, h / 3 + 'px');
}
this.touchmoveY = pageY
}
}
};
</script>
<style>
.bounce {
width: 200vh;
background: skyblue;
margin-top: 100rpx;
}
.box {
width: 100%;
transition: all .1s ease-out;
}
</style>
移动端
<template>
<div class="bounce" :style="{ transform: 'translateY(' + translateY + ')' }" @touchstart="touchstart" @touchend="touchend" @touchmove="touchmove">
<div class="box">
<div v-for="i in 20" :key="i">{{ i }}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
pageY: 0,
translateY: '0px',
touchmoveY: 0,
};
},
methods: {
getTranslateY(h) {
return h + 'px';
},
touchstart(e) {
this.pageY = e.touches[0].pageY;
},
touchend(e) {
this.translateY = this.getTranslateY(0);
},
touchmove(e) {
let pageY = Math.ceil(e.touches[0].pageY);
let h = pageY - this.pageY;
if (h < 0 && pageY < this.touchmoveY && pageY >= 200) {
this.translateY = this.getTranslateY(h / 2);
} else {
this.translateY = this.getTranslateY(h / 3);
}
this.touchmoveY = pageY;
}
}
};
</script>
<style>
.bounce {
width: 50vh;
background: skyblue;
margin-top: 100rpx;
overflow: hidden; /* 防止内容溢出 */
user-select: none;
}
.box {
width: 100%;
transition: transform .3s ease-out;
}
</style>
PC版 与移动端同理