#javascript #reactjs #carbon-design-system
Вопрос:
Я использую компонент SideNav Carbon в качестве элемента управления навигацией по дереву для страницы. Листья могут быть заданы active
либо isActive
логическим свойством, либо путем добавления aria-current='page'
. Если лист находится в подменю, меню расширяется, если активен какой-либо из его дочерних элементов. Отслеживание активных товаров не выходит из коробки, его нужно добавить. У меня есть два вопроса:
- Каков был бы правильный способ реализации активного отслеживания товаров? Я могу придумать два способа: добавить
onClick()
к каждомуSideNavMenuItem
или, как я это сейчас реализовал: собрать массив ссылок, затемuseEffect()
удалить активный класс из всех и добавить его в выбранный - Как правильно пометить активный элемент при монтировании содержащего его компонента (например, при обновлении страницы или переходе на страницу с помощью закладки). Мой ссылочный код устанавливает активное состояние, добавляя требуемый класс в пункт меню, но
SideNavMenu
он откроется только в том случае, если активен какой — либо из его дочерних элементов, что является свойством, которое я не могу установить с помощью ссылки.
Мой текущий пример основан на небольшом дереве из 8 элементов, но мне придется расширить его до гораздо большего масштаба.
const MySidebar = () => {
const menuRefs = useRef(new Array());
useEffect(() => {
const className = "bx--side-nav__link--current";
menuRefs.current.forEach(ref => {ref.classList.remove(className)})
const ref = menuRefs.current.filter((ref) => ref.baseURI === ref.href);
if (ref) {
ref[0].classList.add(className);
}
});
return (
<SideNav
className="my-nav"
isFixedNav
expanded={true}
isChildOfHeader={false}
aria-label="Side navigation"
>
<SideNavItems>
<SideNavMenuItem ref={(element) => menuRefs.current[0] = element} element={Link} to="page1">Page 1</SideNavMenuItem>
<SideNavMenuItem ref={(element) => menuRefs.current[1] = element} element={Link} to="page2">Page 2</SideNavMenuItem>
<SideNavMenu title='Some submenu'>
<SideNavMenuItem ref={(element) => menuRefs.current[2] = element} element={Link} to="page3">Page 3</SideNavMenuItem>
<SideNavMenuItem ref={(element) => menuRefs.current[3] = element} element={Link} to="page4">Page 4</SideNavMenuItem>
<SideNavMenuItem ref={(element) => menuRefs.current[4] = element} element={Link} to="page5">Page 5</SideNavMenuItem>
<SideNavMenuItem ref={(element) => menuRefs.current[5] = element} element={Link} to="page6">Page 6</SideNavMenuItem>
<SideNavMenuItem ref={(element) => menuRefs.current[6] = element} element={Link} to="page7">Page 7</SideNavMenuItem>
</SideNavMenu>
<SideNavMenuItem ref={(element) => menuRefs.current[7] = element} element={Link} to="page8">Page 8</SideNavMenuItem>
</SideNavItems>
</SideNav>
);
};
Ответ №1:
Наличие активного элемента в памяти-это не лучший способ, afais, вы должны сделать вывод об этом по URL-адресу. Вы можете использовать hashed routes
или route parameters
для отслеживания активного элемента, нажать его на URL-адрес после нажатия, использовать его непосредственно из URL-адреса в компоненте. Таким образом, он не потеряет активный элемент при обновлении, а URL-адреса также можно добавлять в закладки и делиться ими.
Комментарии:
1. Активный элемент не сохраняется в памяти. URL-адрес указывает, какой из них является активным, поскольку каждый элемент загружает определенную страницу. Что мне трудно понять, так это то, как я могу связать URL-адрес со свойством элемента
isActive
2. @RekaB ты используешь
ReactRouter
? так, например , если вы нажмете активный элемент для поиска параметров, это будет похоже на то, какhttp://localhost:300/home?page=page6
вы могли бы получить значениеwindow.location.search
, если оно находится в пути, вам придется выполнить некоторую обработку строк. Если вы используете react-маршрутизатор, который рекомендуется, проще было быmatch.params.{paramId}
получить доступ к параметрам пути. для поиска же.3. проблема не в том, чтобы определить, активна ли страница, а в том, чтобы элемент SideNav осознал это. Теперь я решил проблему, используя
NavLink
вместоLink
этого, но мне все еще нужно иметь возможность открыть SideNavMenu. Меня также интересовала общая передовая практика настройки свойств потенциально динамически генерируемых детей4. @RekaB, если вы можете предоставить codesandbox.io минимальный пример, я могу помочь.
5. разве это не отслеживание активной страницы? в чем проблема ?
Ответ №2:
Для открытия элементов дерева/отслеживания, когда пользователи переходят по ссылкам внутри раздела содержимого, я закончил тем, что обернул оригинал SideNavMenu
своим собственным компонентом, который рекурсивно проверяет, есть ли у кого-либо из детей ссылка на текущее местоположение. Я разделил проверку на три метода, чтобы if
ни в одном из них не было поля утверждений. Я все еще не знаю, правильный ли это подход, но он работает.
class MySideNavMenu extends React.Component {
hasActiveChild = (child) => {
if (child.props.element) { // leaf
return this.props.location.pathname === child.props.to;
}
if (child.props.children) { // node
return this.checkChildren(child.props.children);
}
};
checkChildren = (children) => {
return Array.isArray(children)
? children.some((child) => {
return this.hasActiveChild(child);
})
: this.hasActiveChild(children);
};
isExpanded = () => {
const children = this.props.children;
if (children) {
// if we have children, either a single or multiple, find if it is active
return this.checkChildren(children);
}
return false;
};
render() {
return (
<SideNavMenu defaultExpanded={this.isExpanded()} title={this.props.title}>
{this.props.children}
</SideNavMenu>
);
}
}
export default withRouter(MySideNavMenu);