更改材质UI列表按钮事件中所选项目的颜色

问题描述 投票:0回答:4

我有带有按钮的侧边栏,当我单击一个按钮时,我想在选定的按钮上设置颜色,但它无法正常工作,因为有时需要单击两次才能设置颜色,我不知道为什么。当我设置 setSelectedIndex(1) 但在 console.log(selectedIndex) 中显示 0

import { Drawer, List, ListItem, ListItemButton, ListItemText, styled, Toolbar } from '@mui/material'
import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom';
import { sideItems } from './SideItems';

const Sidebar: React.FC = () => {

    const drawerWidth = 240;
    const navigate = useNavigate();

    const [selectedIndex, setSelectedIndex] = useState(0);

    const StyledListText = styled(ListItemText)({
        textAlign: 'center',
        color: 'white'
    });

    const CustomListButton = styled(ListItemButton)({
        "&.Mui-selected": {
            backgroundColor: "#2e8b57!important"
        }
    });


    const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
        event.preventDefault();
        navigate(path);
        setSelectedIndex(index);
    }

    return (
        <Drawer
            variant="permanent"
            sx={{
                width: drawerWidth,
                [`& .MuiDrawer-paper`]: { width: drawerWidth, boxSizing: 'border-box' }
            }}
            PaperProps={{
                elevation: 12,
                sx: {
                    width: 240,
                    backgroundColor: "primary.light"
                }
            }}
        >
            <Toolbar />
            <List>
                {sideItems.map((item, index) =>
                    <ListItem key={item.id}>
                        <CustomListButton selected={index === selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}>
                            <StyledListText primary={item.text} />
                        </CustomListButton>
                    </ListItem>
                )}
            </List>

        </Drawer>
    )
}

export default Sidebar
reactjs typescript material-ui
4个回答
1
投票

最有可能的是,您将

<Sidebar/>
作为子组件包含在每个页面组件的 jsx 中,因此每次您创建它的新实例时,由于初始
selectedIndex
值为 0,因此它始终是选择的第一个项目无论您使用
navigate
重定向到哪个页面组件,除非您单击另一个按钮来更新此新
selectedIndex
实例的
Sidebar
值。

您应该如何在顶层使用

<Sidebar/>
来创建它的一个实例,这样它就不会丢失它的
hooks
值,如下所示:

function Layout(props) {
  return (
    <Fragment>
      <Siderbar/>
      <main>{props.children}</main>
    </Fragment>
  );
}
function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Head>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </Head>
      <Component {...pageProps} />
    </Layout>
  );

1
投票

你可以更好地写你的问题:

  1. 本例中不需要写:
import { useNavigate } from 'react-router-dom';
import { sideItems } from './SideItems';
  1. 您必须在示例中编写 const sideItems
const sideItems = [
  {
    id: '1',
    text: 'lalala',
    path: 'lololo'
  }
]

解决方案:

  1. 您可以编写解决方案 - 布尔值:

(改变你的琴弦)

const [selectedIndex, setSelectedIndex] = useState(true);
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
  event.preventDefault();
  setSelectedIndex(!selectedIndex);
}
<CustomListButton selected={selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}>
  1. 您可以写下解决方案 - 编号:

(改变你的琴弦)

const [selectedIndex, setSelectedIndex] = useState(0);
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
  event.preventDefault();
  setSelectedIndex((prev) => {
    return prev ? 0 : 1
  });
}
<CustomListButton selected={!!selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}>


1
投票

谢谢你们的帮助,我找到了适合我的案例的解决方案 我添加了

import { Link } from 'react-router-dom';

休息看起来像

{sideItems.map((item) =>
    <ListItemButton sx={{
        "&.Mui-selected": {
            backgroundColor: "#2e8b57!important"
        }
    }} key={item.id} component={Link} to={item.path} selected={location.pathname === item.path}>
        <StyledListText primary={item.text} />
    </ListItemButton>
)}

0
投票

这会起作用。基本上,selected 属性告诉“&.Mui-selected”它是选定的。我将 selectedIndex 设置为 -1,因此没有选择任何内容。当调用 onClick 时,我将 selectedIndex 更新为所选行。在 ListItemButton 小部件中,仅当 {props.index === props.onSelectedIndex} 时,selected 才会设置为 true。当选择新的 ListItemButton 时,它的选择设置为 true,而旧的 ListItemButton 现在设置为 false。至于“&.Mui-selected”,它将选定的ListItemButton更改为新的背景颜色红色。使用默认的黑色字体,如果人们认为在代码审查后很难阅读红底黑字,我可能会将其更改为白色等颜色。

在功能 Row 中我添加了一个列表行,重要的部分是 sx 设置和 selected= 行。

function Row(props) {
    return (
        <ListItem disablePadding>

            <ListItemButton
                sx={{
                    height: '1.5rem',
                    border: 1,
                    "&.Mui-selected": {
                        backgroundColor: "red",
                    },
                    "&.Mui-focusVisible": {
                        backgroundColor: "#2e8b57",
                        color: 'white',
                    },
                    ":hover": {
                        backgroundColor: "#2e8b57",
                        color: 'white',
                    }
                }}
                onClick={(e) => props.onClick(e, props.index, props.data["name"], props.data["id"])}
                selected={props.index === props.onSelectedIndex}
            >
                <ListItemText primary={props.data["name"]}/>
            </ListItemButton>
        </ListItem>
    );
}

这是主要功能部分:

const [selectedIndex, setSelectedIndex] = useState(-1);

const selectedSnapShot = (e, index, name, id) => {
    e.preventDefault();
    setSelectedIndex(index);
}

现在调用 Row 将项目添加到列表中

{
  data && data['snapshotList'].map((item, index) => {
    return (<Row key={"s" + index} data={item} index={index} onClick={selectedSnapShot} onSelectedIndex={selectedIndex}/>)
  })
}

当您将鼠标悬停在一条线上时,它的颜色会更改为绿底白字,当您选择一条线时,颜色会永久更改为红底黑字。

© www.soinside.com 2019 - 2024. All rights reserved.