vue实现滑动吸附
Vue 实现滑动吸附效果
滑动吸附效果常见于移动端页面,当用户滑动到特定位置时内容自动吸附到边界。以下是几种实现方法:
使用 CSS scroll-snap
CSS 原生支持滚动吸附,无需 JavaScript 介入,性能最佳:

<template>
<div class="snap-container">
<div class="snap-item">Item 1</div>
<div class="snap-item">Item 2</div>
<div class="snap-item">Item 3</div>
</div>
</template>
<style scoped>
.snap-container {
scroll-snap-type: y mandatory;
overflow-y: scroll;
height: 100vh;
}
.snap-item {
scroll-snap-align: start;
height: 100vh;
}
</style>
结合 IntersectionObserver API
通过监听元素进入视口的比例实现精准控制:
import { ref, onMounted } from 'vue'
export default {
setup() {
const containerRef = ref(null)
onMounted(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0.5) {
entry.target.scrollIntoView({
behavior: 'smooth'
})
}
})
}, {
threshold: [0, 0.5, 1],
root: containerRef.value
})
document.querySelectorAll('.snap-item').forEach(el => {
observer.observe(el)
})
})
return { containerRef }
}
}
第三方库解决方案
使用 vueuse 的 useScroll 组合式函数:

import { useScroll } from '@vueuse/core'
export default {
setup() {
const el = ref(null)
const { y } = useScroll(el)
watch(y, (newY) => {
const itemHeight = window.innerHeight
const nearestIndex = Math.round(newY / itemHeight)
el.value.scrollTo({
top: nearestIndex * itemHeight,
behavior: 'smooth'
})
})
return { el }
}
}
移动端优化技巧
添加 touch 事件处理提升移动端体验:
const handleTouchEnd = (e) => {
const deltaY = e.changedTouches[0].clientY - startY.value
const direction = deltaY > 0 ? 1 : -1
const currentIndex = Math.round(scrollY.value / window.innerHeight)
const targetIndex = Math.max(0, currentIndex + direction)
containerRef.value.scrollTo({
top: targetIndex * window.innerHeight,
behavior: 'smooth'
})
}
性能优化建议
避免在滚动事件中执行昂贵操作,使用防抖处理:
import { debounce } from 'lodash-es'
const checkSnapPosition = debounce(() => {
// 吸附逻辑
}, 100)
window.addEventListener('scroll', checkSnapPosition)
以上方法可根据具体需求组合使用,CSS 方案适合简单场景,JavaScript 方案提供更精细控制,第三方库能减少开发成本。实际实现时应考虑浏览器兼容性和移动端手势交互体验。






