英文:
Hover states on React nested menu
问题
在以下代码中,我有一个嵌套菜单。在悬停时,我希望将 selected
类名称添加到 Nav.Item,并且仅在我悬停到另一个 Nav.Item
上时将其移除。我可以通过 onMouseOver
来实现这一点。不幸的是,它不会向任何子级 Nav.Item
添加 selected
类。
因此,要求如下:
- 对于悬停在任何 nav.item 上,应添加 selected 类
- 如果鼠标离开项目,则不要删除
selected
类 - 当出现子菜单时,在
Nav.Item
上保留selected
类 - 只有在悬停到另一个相同级别的
Nav.Item
上时才移除selected
类
"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;
希望有人能帮助您解决这个问题。
英文:
In the following code I have a nested menu. On hover I wanted to add selected
class name to the Nav.Item and only remove it when I hover over another Nav.Item
. I could achive that with onMouseOver
. Unfortunately, it doesn't add selected
class to any of the sub-level Nav.Item
.
So the criterias would be:
for hover on any nav.item selected class should be added
- don't remove
selected
class if mouse leaves the item - keep
selected
class on theNav.Item
when a child menu appears - remove
selected
class only, if hover over anotherNav.Item
but on the same level
"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;
I hope someone can help with it.
答案1
得分: 1
请尝试以下代码:
function hasSelectedChild(menuItem) {
return menuItem.children && menuItem.children.length > 0 && menuItem.children.find(item => item.id === selectedItemId || hasSelectedChild(item))
}
function renderMenuItems(menuItems) {
return menuItems.map(item => (
<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>
));
}
希望这有帮助。
英文:
Try this:
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>
));
}
答案2
得分: 1
为了实现在鼠标悬停在Nav.Item元素上时添加"selected"类,并在出现子菜单时保持该类,您可以按照以下方式修改代码:
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;
在嵌套的Nav组件上添加了className属性,以在选定父级Nav.Item时添加"selected"类。并且添加了onMouseLeave={handleItemMouseLeave}事件处理程序到Nav.Item上,以触发selectedItemId的重置。
英文:
To achieve the desired behavior of adding the "selected" class to the Nav.Item elements on hover and keeping it when a child menu appears, you can modify the code as below:
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;
Adding the className prop to the nested Nav component to add the "selected" class when the parent Nav.Item is selected. And adding the onMouseLeave={handleItemMouseLeave} event handler to the Nav.Item to trigger the reset of selectedItemId
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论