lenis选项卡举例
<div class="tabs"><!-- 选项卡导航 --><nav class="tab-nav"><button data-tab="tab1" class="active">Tab 1</button><button data-tab="tab2">Tab 2</button><button data-tab="tab3">Tab 3</button></nav><!-- 选项卡内容容器 --><div class="tab-content active" id="tab1"><div class="scroll-content"> <!-- 滚动内容区1 --> </div></div><div class="tab-content" id="tab2"><div class="scroll-content"> <!-- 滚动内容区2 --> </div></div><div class="tab-content" id="tab3"><div class="scroll-content"> <!-- 滚动内容区3 --> </div></div>
</div>
CSS 关键样式
.tabs {height: 100vh;display: flex;flex-direction: column;
}.tab-content {flex: 1;overflow: hidden; /* 隐藏原生滚动条 */position: relative;
}.scroll-content {height: 100%; /* 关键:使内容区可滚动 */padding: 20px;
}
JavaScript 核心逻辑
初始化 Lenis 管理器
class TabLenisManager {constructor() {this.currentLenis = nullthis.tabs = {}}// 创建选项卡实例create(tabId) {if (this.tabs[tabId]) returnconst wrapper = document.getElementById(tabId)const content = wrapper.querySelector('.scroll-content')this.tabs[tabId] = new Lenis({wrapper: wrapper, // 容器元素content: content, // 内容元素duration: 1.2,smoothWheel: true})// 保存滚动位置this.tabs[tabId].scroll = 0}// 切换选项卡switch(tabId) {// 停止当前实例if (this.currentLenis) {this.currentLenis.stop()this.currentLenis.scroll = this.currentLenis.animatedScroll}// 初始化新实例if (!this.tabs[tabId]) {this.create(tabId)}this.currentLenis = this.tabs[tabId]this.currentLenis.start()this.currentLenis.scrollTo(this.currentLenis.scroll)}
}
初始化与事件绑定
const tabManager = new TabLenisManager()// 初始化第一个选项卡
tabManager.create('tab1')
tabManager.switch('tab1')// 选项卡切换事件
document.querySelectorAll('[data-tab]').forEach(btn => {btn.addEventListener('click', () => {const tabId = btn.dataset.tabtabManager.switch(tabId)})
})
功能增强建议
动态内容处理
当选项卡内容变化时,调用:
tabManager.currentLenis.resize()
保存滚动位置
在切换时记录位置:
class TabLenisManager {constructor() {this.scrollPositions = {}}switch(tabId) {// 保存旧位置if (this.currentLenis) {this.scrollPositions[this.currentTabId] = this.currentLenis.scroll}// 恢复新位置if (this.scrollPositions[tabId]) {this.currentLenis.scrollTo(this.scrollPositions[tabId])}}
}
响应式高度调整
function setTabHeight() {const navHeight = document.querySelector('.tab-nav').offsetHeightdocument.querySelectorAll('.tab-content').forEach(tab => {tab.style.height = `calc(100vh - ${navHeight}px)`})
}window.addEventListener('resize', setTabHeight)
setTabHeight()
性能优化
1. 实例销毁策略
// 最多保留2个非活动实例
const MAX_CACHED = 2class TabLenisManager {switch(tabId) {// 清除多余实例const keys = Object.keys(this.tabs)if (keys.length > MAX_CACHED) {const toRemove = keys.filter(k => k !== tabId).pop()this.tabs[toRemove].destroy()delete this.tabs[toRemove]}}
}
滚动事件代理
const handleScroll = (e) => {if (tabManager.currentLenis) {// 阻止原生滚动e.preventDefault()tabManager.currentLenis.scrollTo(tabManager.currentLenis.scroll + e.deltaY)}
}document.querySelectorAll('.tab-content').forEach(tab => {tab.addEventListener('wheel', handleScroll, { passive: false })
})
完整 React 示例
import { useEffect, useRef } from 'react'
import Lenis from '@studio-freight/lenis'function Tabs() {const lenisRefs = useRef({})const activeTab = useRef('tab1')// 初始化实例const initLenis = (tabId) => {const wrapper = document.getElementById(tabId)const content = wrapper.querySelector('.scroll-content')lenisRefs.current[tabId] = new Lenis({wrapper,content,smoothWheel: true})}// 切换处理const switchTab = (tabId) => {// 保存旧位置const prevLenis = lenisRefs.current[activeTab.current]prevLenis.stop()// 初始化新实例if (!lenisRefs.current[tabId]) {initLenis(tabId)}const newLenis = lenisRefs.current[tabId]newLenis.start()activeTab.current = tabId}// 清理useEffect(() => {initLenis('tab1')return () => {Object.values(lenisRefs.current).forEach(lenis => lenis.destroy())}}, [])return (<div className="tabs">{/* 导航与内容结构同上 */}</div>)
}
通过这种实现方式,每个选项卡将拥有:
✅ 独立的滚动实例
✅ 平滑滚动效果
✅ 滚动位置记忆
✅ 自动高度适配
✅ 资源自动回收
可根据实际需求调整 MAX_CACHED
参数平衡内存占用与切换流畅度。