提问人:levipadre 提问时间:7/13/2023 最后编辑:levipadre 更新时间:7/13/2023 访问量:68
React 嵌套菜单上的悬停状态
Hover states on React nested menu
问:
在下面的代码中,我有一个嵌套菜单。悬停时,我想将类名添加到 Nav.Item 中,并且仅在将鼠标悬停在另一个 .我可以用.不幸的是,它不会将类添加到任何子级别。selected
Nav.Item
onMouseOver
selected
Nav.Item
因此,标准是: 对于将鼠标悬停在任何 Nav.Item 上,应添加选定的类
- 如果鼠标离开项目,则不删除类
selected
- 将类保留在“出现子菜单时”上
selected
Nav.Item
- 仅删除类,如果将鼠标悬停在另一个类上但在同一级别上
selected
Nav.Item
"use client";
import Nav from 'react-bootstrap/Nav';
import Link from 'next/link';
import { getMenu } from '@/lib/APIs/menu';
import { use, useEffect, useRef, useState } from 'react';
import { usePathname } from 'next/navigation';
import { Button, NavDropdown } from 'react-bootstrap';
const dataPromise = getMenu();
const GlobalNav = () => {
const MENU = use(dataPromise);
const [selectedItemId, setSelectedItemId] = useState<string | null>(null);
function handleItemHover(itemId: string) {
setSelectedItemId(itemId);
}
function renderMenuItems(menuItems: any[]) {
return menuItems.map((item: any) => (
<Nav.Item
as='li'
key={item.id}
onMouseOver={() => handleItemHover(item.id)}
className={selectedItemId === item.id ? 'selected' : ''}
>
<Nav.Link
as={Link}
href={item.url}
>
<span>
{item.title}
</span>
</Nav.Link>
{item.children && item.children.length > 0 && (
<Nav as='ul'>
{renderMenuItems(item.children)}
</Nav>
)}
</Nav.Item>
));
}
return (
<Nav as='ul'>
{renderMenuItems(MENU)}
</Nav>
);
}
export default GlobalNav;
我希望有人能帮忙。
答:
1赞
Emil J
7/13/2023
#1
试试这个:
function hasSelectedChild(menuItem) {
return menuItem.children && menuItem.children.length > 0 && menuItem.children.find(item => item.id === selectedItemId || hasSelectedChild(item))
}
function renderMenuItems(menuItems: any[]) {
return menuItems.map((item: any) => (
<Nav.Item
as='li'
key={item.id}
onMouseOver={(e) => {
e.stopPropagation();
handleItemHover(item.id)
}}
className={(hasSelectedChild(item) || selectedItemId === item.id) ? 'selected' : ''}
>
<Nav.Link
as={Link}
href={item.url}
>
<span>
{item.title}
</span>
</Nav.Link>
{item.children && item.children.length > 0 && (
<Nav as='ul'>
{renderMenuItems(item.children)}
</Nav>
)}
</Nav.Item>
));
}
评论
0赞
levipadre
7/13/2023
谢谢 @Emil J,它几乎是完美的,但现在当我将鼠标悬停在第一级上时,它会为第二级、第三级等的所有 s 添加类,而不仅仅是我悬停在上面的那个。Nav.Item
selected
Nav.Item
0赞
Emil J
7/13/2023
啊,好的,那么我会写一个函数来检查一个项目是否有一个选定的子项。像这样递归的东西:并使用它来设置 className,如下所示:function hasSelectedChild(menuItem) { return menuItems.children.length > 0 && menuItems.children.find(item => item.id === selectedItemId || hasSelectedChild(item)) }
className={hasSelectedChild(item) || selectedItemId === item.id ? 'selected' : ''}
0赞
Emil J
7/13/2023
我现在使用这种方法更新了我的答案
1赞
Emil J
7/13/2023
现在,我再次编辑了我的答案,以阻止 mouseOver 事件传播到父导航项。测试过它,似乎可以:)
1赞
levipadre
7/13/2023
它确实有效!非常感谢你@Emil J,你是救命恩人。
1赞
KGS
7/13/2023
#2
若要实现在悬停时将“selected”类添加到 Nav.Item 元素并在出现子菜单时保留该类的预期行为,可以按如下方式修改代码:
import Nav from 'react-bootstrap/Nav';
import Link from 'next/link';
import { getMenu } from '@/lib/APIs/menu';
import { usePathname } from 'next/navigation';
import { Button, NavDropdown } from 'react-bootstrap';
const dataPromise = getMenu();
const GlobalNav = () => {
const MENU = use(dataPromise);
const [selectedItemId, setSelectedItemId] = useState<string | null>(null);
function handleItemHover(itemId: string) {
setSelectedItemId(itemId);
}
function handleItemMouseLeave() {
setSelectedItemId(null);
}
function renderMenuItems(menuItems: any[]) {
return menuItems.map((item: any) => (
<Nav.Item
as='li'
key={item.id}
onMouseOver={() => handleItemHover(item.id)}
onMouseLeave={handleItemMouseLeave}
className={selectedItemId === item.id ? 'selected' : ''}
>
<Nav.Link as={Link} href={item.url}>
<span>{item.title}</span>
</Nav.Link>
{item.children && item.children.length > 0 && (
<Nav as='ul' className={selectedItemId === item.id ? 'selected' : ''}>
{renderMenuItems(item.children)}
</Nav>
)}
</Nav.Item>
));
}
return (
<Nav as='ul'>
{renderMenuItems(MENU)}
</Nav>
);
}
export default GlobalNav;
将 className 属性添加到嵌套的 Nav 组件中,以在选择父 Nav.Item 时添加“selected”类。并将 onMouseLeave={handleItemMouseLeave} 事件处理程序添加到 Nav.Item 以触发 selectedItemId 的重置
评论