官网
lenis - npm
方法一:基础判断(推荐)
通过 Lenis 自带的 scroll
和 limit
属性直接判断:
const lenis = new Lenis()
// 滚动事件监听
lenis.on('scroll', ({ scroll, limit }) => {
const distanceToBottom = limit - scroll
const threshold = 100 // 距离底部100px触发
if (distanceToBottom < threshold) {
console.log('接近底部')
// 执行加载更多等操作
}
})
方法二:动态内容适配
当页面内容动态增加时,需要 重置 Lenis 的尺寸计算:
// 加载新内容后调用
function loadMoreData() {
fetch('/api/data').then(() => {
// 1. 插入新内容到DOM
// 2. 通知Lenis重新计算
lenis.resize() // 关键方法
})
}
// 在滚动监听中
lenis.on('scroll', ({ scroll, limit }) => {
if (limit - scroll < 100) {
loadMoreData()
}
})
方法三:精确计算模式
针对复杂布局(如存在浮动元素、position: sticky 等):
function isBottom() {
// 获取 Lenis 的滚动容器
const wrapper = lenis.wrapperElement || document.documentElement
// 精确计算可滚动范围
const actualLimit = wrapper.scrollHeight - wrapper.clientHeight
const currentScroll = lenis.scroll
return currentScroll >= actualLimit - 1 // 消除计算误差
}
// 使用示例
if (isBottom()) {
console.log('精确到达底部')
}
⚠️ 注意事项
-
性能优化
在滚动事件中使用防抖(建议直接使用 Lenis 的 RAF 机制):
function checkBottom() { if (lenis.isScrolling) return // 滚动中不检测 // 检测逻辑 }
移动端适配
兼容触摸屏惯性滚动
lenis.on('scroll', ({ scroll, limit, velocity }) => { if (velocity > 0.1 && limit - scroll < 500) { // 快速滑动时提前加载 } })
方向判断
只在下滑时检测:
let lastScroll = 0 lenis.on('scroll', ({ scroll }) => { const isScrollingDown = scroll > lastScroll lastScroll = scroll if (isScrollingDown && isBottom()) { // 处理底部逻辑 } })
完整示例(React 版)
import { useEffect, useRef } from 'react' import Lenis from '@studio-freight/lenis' function App() { const lenisRef = useRef() useEffect(() => { const lenis = new Lenis() lenisRef.current = lenis const checkBottom = () => { const { scroll, limit } = lenis if (limit - scroll < 100) { console.log('触发加载') // 此处执行加载逻辑 } } const raf = (time) => { lenis.raf(time) checkBottom() requestAnimationFrame(raf) } requestAnimationFrame(raf) return () => lenis.destroy() }, []) return ( <div>{/* 页面内容 */}</div> ) }
回调函数中的实参limit
-
-
关键特性
动态计算
Lenis 的阻尼效果会使实际滚动值略微超过 limit
,但最终会回弹到 limit
值:
3. 边界缓冲
- 当页面高度变化时(例如加载更多内容),需手动调用
lenis.resize()
更新:// 加载新内容后 document.body.appendChild(newContent) lenis.resize() // 重新计算 limit
方向差异
- 垂直滚动:
limit = scrollHeight - innerHeight
- 水平滚动:
limit = scrollWidth - innerWidth
(需配置 Lenis 为横向滚动)
// 启用阻尼效果后
console.log(lenis.isScrolling) // 当滚动超过 limit 时为 true
应用场景
1. 无限滚动加载
lenis.on('scroll', ({ scroll, limit }) => {
if (limit - scroll < 100) {
loadMoreContent()
}
})
返回顶部按钮
const showButton = scroll > 0.3 * limit
进度指示器
const progress = Math.min(scroll / limit, 1)
对比原生属性
场景 | 原生方法 | Lenis 方法 | 优势 |
---|---|---|---|
静态页面 | window.scrollY + scrollHeight 计算 | 直接使用 limit | 无需手动计算 |
动态加载内容 | 需监听 DOM 变化并重新计算 | 调用 resize() 即可 | 自动处理复合滚动容器 |
有 transform 的容器 | 可能计算错误 | 结果准确 | 正确处理 CSS transform 和复杂布局 |
横向滚动 | 需单独处理 scrollWidth | 统一使用 limit | 代码逻辑一致 |
六、特殊案例处理
存在 position: sticky
元素
// 手动补偿 sticky 元素高度
const stickyElement = document.querySelector('.sticky')
const adjustedLimit = limit - stickyElement.offsetHeight
多滚动容器
如果 Lenis 被配置为控制某个子容器:
const lenis = new Lenis({
wrapper: document.getElementById('custom-scroll-container'),
content: document.getElementById('custom-content')
})
// 此时 limit 对应的是容器内部的滚动极限
通过理解 limit
的含义和使用场景,可以更高效地开发与滚动相关的交互功能,同时避免手动计算滚动边界的繁琐操作。