SideBar 侧边导航与内容区域交互重写【Ant Design Mobile】

需求:SideBar 侧边导航与内容区域交互

  1. 点击侧边栏某一项时,相对应内容区域滚动到视口顶部
  2. 滚动视口区域,到某一项内容区域,侧边栏选中状态也会跟着变化
typescript 复制代码
const SideBarAgain: React.FC<PopupProps> = (props) => {

  // 父组件传过来的值
  const { tabList } = props

  const mainElementRef = useRef<HTMLDivElement>(null)
  // 用来监听页面滚动事件
  const scroll = useScroll(mainElementRef);

  const mainElement = mainElementRef.current

  const state = useReactive({ activeKey: '1' });

  const handleScroll = (key?:string) => {
    
    // 滚动时,需要修改侧边栏选中状态
    // 过滤出元素顶部到视窗的距离大于0的元素
    const currentKey = tabList.filter((item: { key: string })=>{
      const element = document.getElementById(`anchor-${item.key}`)
        if (!element) return
        const rect = element.getBoundingClientRect()
        if (rect.top >= 0) {
          return item
        }
    })
    
    // 判断如果currentKey大于0,则选取第一个key值
    if(currentKey.length){
      state.activeKey = currentKey[0].key
    }else{
      state.activeKey = tabList[tabList.length-1].key
    }
     
    // 点击侧边栏传入的ID,并滚动到对应位置
    if(key){
      document.getElementById(`anchor-${key}`)?.scrollIntoView({behavior: "smooth"})
      state.activeKey = key
    }
  }

  useEffect(() => {
    if (!mainElement) return
    mainElement.addEventListener('scroll', () => handleScroll)
    return () => {
      mainElement.removeEventListener('scroll', () => handleScroll)
    }
  }, [])

  // 利用scroll的变化监听handleScroll
  useLayoutEffect(() =>  handleScroll,[scroll])

  return (
       <div className='sider'>
          <SideBar activeKey={state.activeKey} onChange={(key)=>handleScroll(key)}>
            {tabList.map((item: { key: string, title: string }) => (
              <SideBar.Item key={item.key} title={item.title} />
            ))}
          </SideBar>
          <div className='main' ref={mainElementRef}>
            {tabList.map((item: { key: string; title: string; text: string}) => (
              <div key={item.key} id={`anchor-${item.key}`} >
                <h2>{item.title}</h2>
                {item.text}
              </div>
            ))}
          </div>
       </div>
  )
}

export default SideBarAgain;
相关推荐
梦曦i6 小时前
@meng-xi/create-uni-app vs unibest:轻量脚手架与重型框架的定位之争
前端·uni-app
平头哥技术团队6 小时前
Day 10 | 工欲善其事:VS Code 配置与项目归档
android·开发语言·前端·javascript·html·交互
乌恩大侠6 小时前
GH200 新增 NVMe SSD 分区、格式化与挂载完整流程
运维·服务器·前端
yume_sibai6 小时前
Element Plus 数据展示组件完全指南(15个核心组件)
前端·javascript·vue.js
qiuhaipeng17 小时前
Claude code 升级后上下文长度变短问题
java·前端·数据库
zzz_23687 小时前
个人 AI 记忆如何跨工具复用:用 Markdown、索引和 Skill 搭一个可治理的记忆库
前端·人工智能·react.js·前端框架·agent·agent测评
剑之所向9 小时前
.NET 官方`System.Threading.Channels`
前端·javascript·数据库
计算机魔术师9 小时前
GPT-6 Astra幻觉砍到2%,却被一种老招数轻松绕过
前端
cjy00011110 小时前
2026AI 产品如何从一次性 Demo 变成可重复使用的业务工具?
前端·人工智能·fde
IT_陈寒10 小时前
React的状态更新坑得我差点加班到天亮
前端·人工智能·后端