带有分页和排序的表格内的 Material UI 菜单按钮在第二页后不起作用
Posted
技术标签:
【中文标题】带有分页和排序的表格内的 Material UI 菜单按钮在第二页后不起作用【英文标题】:Material UI menu button inside a table with pagination and sort does not work after second page 【发布时间】:2021-08-27 04:49:47 【问题描述】:我正在使用 React 并使用 Material UI。 我正在构建一个包含多列和多行的表格,每行中的一个单元格是一个菜单按钮,一旦单击它就会打开。
在我向表格添加分页和排序之前,这一切正常。 添加分页和排序后,每行的菜单只会在分页的第一页打开。
似乎在第二页之后,菜单会打开但它没有出现在页面上。它的位置似乎较低,但由于分页,我看不到它。
在使用带有分页的表格时,我如何才能看到位于第二页和之后的行的菜单? 排序时如何在页面中看到菜单?
非常感谢您的帮助。
代码:
import React, useContext, useState from "react";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TablePagination from "@material-ui/core/TablePagination";
import TableSortLabel from "@material-ui/core/TableSortLabel";
import Paper from "@material-ui/core/Paper";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";
import useStyles from "./../styles/tableStyles";
import CurrenciesContext from "./../context/currenciesContext";
import DeleteCurrencyContext from "./../context/deleteCurrencyContext";
import AddToCompareContext from "./../context/addToCompareContext";
function descendingComparator(a, b, orderBy)
if (b[orderBy] < a[orderBy])
return -1;
if (b[orderBy] > a[orderBy])
return 1;
return 0;
function getComparator(order, orderBy)
return order === "desc"
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy);
function stableSort(array, comparator)
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) =>
const order = comparator(a[0], b[0]);
if (order !== 0) return order;
return a[1] - b[1];
);
return stabilizedThis.map((el) => el[0]);
const CurrencyTable = () =>
const BILLION = 1000000000;
const TRILLION = 1000000000000;
const MILLION = 1000000;
const classes = useStyles();
const currencies = useContext(CurrenciesContext);
const addToCompare = useContext(AddToCompareContext);
const deleteCurrency = useContext(DeleteCurrencyContext);
const [openTableMenus, setOpenTableMenus] = useState([]);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [page, setPage] = useState(0);
const [order, setOrder] = useState("asc");
const [orderBy, setOrderBy] = useState("rank");
const handleClickTableMenu = (currency, event) =>
let tableMenus = [...openTableMenus];
const index = currencies.indexOf(currency);
tableMenus[index] = event.currentTarget;
setOpenTableMenus(tableMenus);
;
const handleCloseTableMenu = (currency) =>
let tableMenus = [...openTableMenus];
const index = currencies.indexOf(currency);
tableMenus[index] = null;
setOpenTableMenus(tableMenus);
;
const handleTranformBigNum = (num) =>
if (Math.round(num).toString().length > 12)
return `$(num / TRILLION).toFixed(2)T`;
if (Math.round(num).toString().length > 9)
return `$(num / BILLION).toFixed(2)B`;
if (Math.round(num).toString().length > 6)
return `$(num / MILLION).toFixed(2)M`;
return num.toFixed(2);
;
const handleChangePage = (event, newPage) =>
setPage(newPage);
;
const handleChangeRowsPerPage = (event) =>
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
;
const handleRequestSort = (event, property) =>
const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc");
setOrderBy(property);
;
const createSortHandler = (property) => (event) =>
handleRequestSort(event, property);
;
const handleDeleteCurrency = (currency) =>
console.log("delete", currency);
deleteCurrency(currency);
;
const headCells = [
id: "rank",
label: "#",
,
id: "name",
label: "Name",
,
id: "priceChange1d",
label: "24H Change",
,
id: "price",
label: "Price",
,
id: "priceBtc",
label: "Price in BTC",
,
id: "marketCap",
label: "Market CAP",
,
id: "volume",
label: "Volume 24H",
,
];
console.log("menus anchors: ", openTableMenus);
return (
<React.Fragment>
<h2>Currencies Table</h2>
<TableContainer component=Paper>
<Table className=classes.table aria-label="simple table">
<TableHead>
<TableRow>
headCells.map((headCell) => (
<TableCell
key=headCell.id
align="center"
sortDirection=orderBy === headCell.id ? order : false
>
<TableSortLabel
active=orderBy === headCell.id
direction=orderBy === headCell.id ? order : "asc"
onClick=createSortHandler(headCell.id)
>
headCell.label
</TableSortLabel>
</TableCell>
))
<TableCell align="center">PRICE GRAPH (7D)</TableCell>
<TableCell align="center"></TableCell>
</TableRow>
</TableHead>
<TableBody>
currencies &&
stableSort(currencies, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((currency, index) => (
<TableRow key=currency.id>
<TableCell component="th" scope="row">
currency.rank
</TableCell>
<TableCell align="center">
currency.name
<span className=classes.grey>-currency.symbol</span>
</TableCell>
<TableCell
align="center"
className=
currency.priceChange1d >= 0
? classes.positiveChange
: classes.negativeChange
>`$currency.priceChange1d%`</TableCell>
<TableCell align="center">
`$$currency.price.toFixed(2)`
</TableCell>
<TableCell align="center">currency.priceBtc</TableCell>
<TableCell align="center">
handleTranformBigNum(currency.marketCap)
</TableCell>
<TableCell align="center">
handleTranformBigNum(currency.volume)
</TableCell>
<TableCell align="center">GRAPH</TableCell>
<TableCell align="center">
<IconButton
aria-label=`$currency.name-more`
aria-controls=`$currency.name-menu`
aria-haspopup="true"
onClick=(event) =>
handleClickTableMenu(currency, event)
>
<MenuIcon />
</IconButton>
<Menu
id=`$currency.name-menu`
anchorEl=openTableMenus[index]
keepMounted
open=Boolean(openTableMenus[index])
onClose=(event) => handleCloseTableMenu(currency)
>
<MenuItem
onClick=(event) =>
handleCloseTableMenu(currency);
addToCompare(currency);
>
Add to Compare
</MenuItem>
<MenuItem
onClick=() =>
handleCloseTableMenu(currency);
handleDeleteCurrency(currency);
>
Delete Row
</MenuItem>
</Menu>
</TableCell>
</TableRow>
))
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions=[5, 10, 25, 50]
component="div"
count=currencies.length
rowsPerPage=rowsPerPage
page=page
onChangePage=(event, newPage) => handleChangePage(event, newPage)
onChangeRowsPerPage=(event) => handleChangeRowsPerPage(event)
/>
</React.Fragment>
);
;
export default CurrencyTable;
【问题讨论】:
【参考方案1】:我想通了。 它与使用分页后的列表索引有关。 使用分页时,列表中项目的索引将始终从 0 到每页的项目数,而不是分页前项目在列表中的原始索引。
如果您也遇到此问题,请参阅以下代码以查看答案。
import React, useContext, useState from "react";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TablePagination from "@material-ui/core/TablePagination";
import TableSortLabel from "@material-ui/core/TableSortLabel";
import Paper from "@material-ui/core/Paper";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";
import useStyles from "./../styles/tableStyles";
import CurrenciesContext from "./../context/currenciesContext";
import DeleteCurrencyContext from "./../context/deleteCurrencyContext";
import AddToCompareContext from "./../context/addToCompareContext";
function descendingComparator(a, b, orderBy)
if (b[orderBy] < a[orderBy])
return -1;
if (b[orderBy] > a[orderBy])
return 1;
return 0;
function getComparator(order, orderBy)
return order === "desc"
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy);
function stableSort(array, comparator)
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) =>
const order = comparator(a[0], b[0]);
if (order !== 0) return order;
return a[1] - b[1];
);
return stabilizedThis.map((el) => el[0]);
const CurrencyTable = () =>
const BILLION = 1000000000;
const TRILLION = 1000000000000;
const MILLION = 1000000;
const classes = useStyles();
const currencies = useContext(CurrenciesContext);
const addToCompare = useContext(AddToCompareContext);
const deleteCurrency = useContext(DeleteCurrencyContext);
const [openTableMenus, setOpenTableMenus] = useState([]);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [page, setPage] = useState(0);
const [order, setOrder] = useState("asc");
const [orderBy, setOrderBy] = useState("rank");
const handleClickTableMenu = (currency, index, event) =>
let tableMenus = [...openTableMenus];
tableMenus[index] = event.currentTarget;
setOpenTableMenus(tableMenus);
;
const handleCloseTableMenu = (index) =>
let tableMenus = [...openTableMenus];
tableMenus[index] = null;
setOpenTableMenus(tableMenus);
;
const handleTranformBigNum = (num) =>
if (Math.round(num).toString().length > 12)
return `$(num / TRILLION).toFixed(2)T`;
if (Math.round(num).toString().length > 9)
return `$(num / BILLION).toFixed(2)B`;
if (Math.round(num).toString().length > 6)
return `$(num / MILLION).toFixed(2)M`;
return num.toFixed(2);
;
const handleChangePage = (event, newPage) =>
setPage(newPage);
;
const handleChangeRowsPerPage = (event) =>
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
;
const handleRequestSort = (event, property) =>
const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc");
setOrderBy(property);
;
const createSortHandler = (property) => (event) =>
handleRequestSort(event, property);
;
const handleDeleteCurrency = (currency) =>
deleteCurrency(currency);
;
const headCells = [
id: "rank",
label: "#",
,
id: "name",
label: "Name",
,
id: "priceChange1d",
label: "24H Change",
,
id: "price",
label: "Price",
,
id: "priceBtc",
label: "Price in BTC",
,
id: "marketCap",
label: "Market CAP",
,
id: "volume",
label: "Volume 24H",
,
];
return (
<React.Fragment>
<h2>Currencies Table</h2>
<TableContainer component=Paper>
<Table className=classes.table aria-label="simple table">
<TableHead>
<TableRow>
headCells.map((headCell) => (
<TableCell
key=headCell.id
align="center"
sortDirection=orderBy === headCell.id ? order : false
>
<TableSortLabel
active=orderBy === headCell.id
direction=orderBy === headCell.id ? order : "asc"
onClick=createSortHandler(headCell.id)
>
headCell.label
</TableSortLabel>
</TableCell>
))
<TableCell align="center"></TableCell>
</TableRow>
</TableHead>
<TableBody>
currencies &&
stableSort(currencies, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((currency, index) => (
<TableRow key=currency.id>
<TableCell component="th" scope="row">
currency.rank
</TableCell>
<TableCell align="center">
<div className=classes.icon>
<img
src=currency.icon
alt=`$currency.name icon`
></img>
</div>
currency.name
<span className=classes.grey>-currency.symbol</span>
</TableCell>
<TableCell
align="center"
className=
currency.priceChange1d >= 0
? classes.positiveChange
: classes.negativeChange
>`$currency.priceChange1d%`</TableCell>
<TableCell align="center">
`$$currency.price.toFixed(2)`
</TableCell>
<TableCell align="center">currency.priceBtc</TableCell>
<TableCell align="center">
handleTranformBigNum(currency.marketCap)
</TableCell>
<TableCell align="center">
handleTranformBigNum(currency.volume)
</TableCell>
<TableCell align="center">
<IconButton
aria-label=`$currency.name-more`
aria-controls=`$currency.name-menu`
aria-haspopup="true"
onClick=(event) =>
handleClickTableMenu(currency, index, event)
>
<MenuIcon />
</IconButton>
<Menu
id=`$currency.name-menu`
anchorEl=openTableMenus[index]
keepMounted
open=Boolean(openTableMenus[index])
onClose=(event) => handleCloseTableMenu(index)
>
<MenuItem
onClick=(event) =>
handleCloseTableMenu(index);
addToCompare(currency);
>
Add to Compare
</MenuItem>
<MenuItem
onClick=() =>
handleCloseTableMenu(index);
handleDeleteCurrency(currency);
>
Delete Row
</MenuItem>
</Menu>
</TableCell>
</TableRow>
))
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions=[5, 10, 25, 50]
component="div"
count=currencies.length
rowsPerPage=rowsPerPage
page=page
onChangePage=(event, newPage) => handleChangePage(event, newPage)
onChangeRowsPerPage=(event) => handleChangeRowsPerPage(event)
/>
</React.Fragment>
);
;
export default CurrencyTable;
【讨论】:
以上是关于带有分页和排序的表格内的 Material UI 菜单按钮在第二页后不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Element ui 表格(Table)组件中前端实现数据分页和模糊查询
带有分页和排序的 Spring Boot JPA 规范 API