60 lines
2.1 KiB
React
60 lines
2.1 KiB
React
import React, { useState, useEffect } from 'react';
|
||
import './AnchorNav.css';
|
||
|
||
/**
|
||
* Aurora Admin AnchorNav(React)
|
||
* 对齐 组件7.txt AnchorNav 规范:右侧目录、滚动高亮、层级嵌套、点击平滑滚动
|
||
*
|
||
* props:
|
||
* - items : [{ key, label, children? }](key 对应页面元素 id)
|
||
* - fixed
|
||
* - offset : 滚动偏移(避开吸顶高度)
|
||
*/
|
||
export default function AnchorNav({ items = [], fixed = false, offset = 24 }) {
|
||
const allKeys = [];
|
||
(function collect(list) { list.forEach(i => { allKeys.push(i.key); if (i.children) collect(i.children); }); })(items);
|
||
const [active, setActive] = useState(items[0] ? items[0].key : '');
|
||
|
||
const go = (key) => {
|
||
const el = document.getElementById(key);
|
||
if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - offset, behavior: 'smooth' });
|
||
};
|
||
useEffect(() => {
|
||
const onScroll = () => {
|
||
const pos = window.scrollY + 80;
|
||
let cur = allKeys[0];
|
||
for (const k of allKeys) {
|
||
const el = document.getElementById(k);
|
||
if (el && el.offsetTop <= pos) cur = k;
|
||
}
|
||
setActive(cur);
|
||
};
|
||
window.addEventListener('scroll', onScroll);
|
||
return () => window.removeEventListener('scroll', onScroll);
|
||
}, []);
|
||
|
||
return (
|
||
<nav className={`aa-anchor${fixed ? ' fixed' : ''}`}>
|
||
{items.map(it => (
|
||
<div key={it.key}>
|
||
<button className={`aa-anchor-item${active === it.key ? ' is-active' : ''}`} onClick={() => go(it.key)}>{it.label}</button>
|
||
{it.children && (
|
||
<div className="aa-anchor-sub">
|
||
{it.children.map(c => (
|
||
<button key={c.key} className={`aa-anchor-item${active === c.key ? ' is-active' : ''}`} onClick={() => go(c.key)}>{c.label}</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
</nav>
|
||
);
|
||
}
|
||
|
||
/*
|
||
用法示例:
|
||
import AnchorNav from './AnchorNav';
|
||
const items = [{ key: 'intro', label: '简介' }, { key: 'guide', label: '指南', children: [{ key: 'layout', label: '布局' }] }];
|
||
<AnchorNav items={items} fixed />
|
||
*/
|