下拉菜單在不少網站都能見到,鼠標懸浮在導航元素上時會自動彈出子菜單。css
好處:html
導航的語義化標籤爲 nav,內容爲列表 ul,列表元素水平分佈能夠利用浮動或者 flex。數組
例如:markdown
<nav> <ul> <li>導航1</li> <li>導航2</li> <li>導航3</li> </ul> </nav> 複製代碼
下拉菜單也是列表結構,例如:異步
<nav> <ul> <li> <a>導航1</a> <ul> <li>導航1-1</li> <li>導航1-2</li> <li>導航1-3</li> </ul> </li> <li>導航2</li> <li>導航3</li> </ul> </nav> 複製代碼
若是是非自動(hover)彈出能夠直接用 HTML5/select & options。函數
在鼠標離開 nav-item 及其全部子元素時,關閉 dropdown menu,對應的 DOM Event 是 mouseleave。(不是 mouseout)flex
在鼠標進入 nav-item 根元素時,打開 dropdown menu,對應的 DOM Event 是 mouseenter。(比 mouseover 準確)網站
列表由數組渲染生成,把 items 看做 Functor,將渲染函數應用到每一個元素。即 fmap renderToTSX items。spa
type Anchor = {
name: string
href?: string
}
const Dropdown = ({ items }: { items: Anchor[] }) => (
<ul className="head-dropdown">
{items.map(({ name, href }) => (
<li>
<a href={href}>{name}</a>
</li>
))}
</ul>
)
複製代碼
爲了不因 dropdown menu 動態顯示致使 DOM 結構 reflow,因此利用絕對定位讓它脫離文檔流。code
.head-dropdown { position: absolute; z-index: 999; } 複製代碼
由於要動態顯示 dropdown menu,因此屬於異步的 DOM 操做。使用 setState 來實現。
type NavItemProps = Anchor & {
items: Anchor[]
}
const NavItem = ({ name, href, items }: NavItemProps) => {
const [display, setComponent] = useState(<></>)
const visible = () => setComponent(<Dropdown items={items} />)
const hidden = () => setComponent(<></>)
return (
<li className="nav-item" onMouseEnter={visible} onMouseLeave={hidden}>
<a href={href}>{name}</a>
{display}
</li>
)
}
複製代碼
nav-item 的層疊樣式表。須要兼容 IE10 如下就使用浮動。
.nav-item { float: left; padding: 0 0.5rem; } 複製代碼
const App = () => (
<nav>
<ul>
<NavItem
name="item1"
items={[
{ name: "subitem1", href: "#" },
{ name: "subitem2", href: "#" },
{ name: "subitem3", href: "#" }
]}
/>
</ul>
</nav>
)
複製代碼