如何在 Material UI 中建立增強型傳輸列表?
在這篇文章中,我們將看到一個逐步指南,用於在 React MUI 中建立增強型傳輸列表。
傳輸列表是一種列表型別,允許使用者將一個或多個列表項移動到另一個列表。在這裡,如果第一個列表中有多個專案,並且使用者希望將某些專案傳輸到第二個列表,那麼我們使用傳輸列表元件。在 React MUI 中,沒有專門用於傳輸列表的元件;而是,我們自己建立它。
Material UI 中還有一個增強列表的概念,它只是基本傳輸列表的更高階或增強版本。我們可以在增強列表中包含各種內容,例如複選框、應用自定義顏色等。
建立增強型傳輸列表的步驟
以下是建立 Material UI 中增強型傳輸列表的步驟:
步驟 1:建立 React 應用程式
在 MUI 中建立傳輸列表的第一步是建立一個 React 應用程式。要建立一個新的 React 應用程式,請在您的終端中執行以下命令:
npx create react app formcontrolproject
專案建立完成後,透過執行以下命令導航到其目錄:
cd formcontrolproject
步驟 2:將 MUI 新增到 React
建立 React 應用程式後,是時候將 Material UI 安裝到 React 應用程式中了。要安裝 MUI,請執行以下命令:
npm install @mui/material @emotion/react @emotion/styled
步驟 3:定義專案
在建立傳輸列表之前,我們必須定義列表項,並在左右兩側設定一些值。以下是定義專案項的語法:
const [lftItems, setLftItems] = useState([1, 2, 3 ]); const [rytItems, setRytItems] = useState([4, 5, 6]); const [chosenLftItems, setChosenLftItems] = useState([]); const [chosenRytItems, setChosenRytItems] = useState([]);
步驟 4:建立傳輸按鈕
要傳輸列表項,我們必須定義具有處理函式的傳輸按鈕。以下是如何在 React 中建立四個不同的按鈕:
const handlePush = () => { … }; const handlePull = () => { … }; const selectLftItem = (i) => { … }; const selectRightItem = (i) => { … };
步驟 5:在 Main 中呈現列表項
最後,一旦我們定義了所有處理列表傳輸的函式,我們現在必須使用 Stack 在 App.js 元件中呈現列表項。以下是呈現列表項的語法:
function App() { return ( <Stack> <Stack item sx={{ gap: 2 }}> {lftItems.map((item, index) => ( <ListItem key={index}> … </ListItem> ))} </Stack> <Stack item> <Stack> <Button> > </Button> <Button> < </Button> </Stack> </Stack> <Stack sx={{ gap: 2 }}> {rytItems.map((item, index) => ( <ListItem key={index}> … </ListItem> ))} </Stack> </Stack> ) } export default App;
就是這樣!現在我們已經成功地學習了在 MUI 中建立增強型傳輸列表的步驟。所以,讓我們看看一些不同方法的示例。
示例
在此示例中,我們建立了一個自定義的增強型傳輸列表,當用戶選擇任何要傳輸的專案時,複選框將被啟用。在這裡,使用者還可以一次選擇所有列表項以傳輸到其他列表。
import React from "react"; import { useState } from "react"; import { Stack } from "@mui/material"; import {List, ListItem, ListItemText, ListItemIcon} from '@mui/material'; import Checkbox from '@mui/material/Checkbox'; import Button from '@mui/material/Button'; import {Card, CardHeader} from '@mui/material/'; function not(a, b) { return a.filter((value) => b.indexOf(value) === -1); } function intersection(a, b) { return a.filter((value) => b.indexOf(value) !== -1); } function union(a, b) { return [...a, ...not(b, a)]; } const App = () => { const [chk, setChk] = useState([]); const [lftItems, setLftItems] = useState(["Item 11", "Item 12", "Item 13", "Item 14", "Item 15"]); const [rightItems, setRightItems] = useState(["Item 21", "Item 22", "Item 23", "Item 24", "Item 25"]); const chkLeftChecked = intersection(chk, lftItems); const chkRightChecked = intersection(chk, rightItems); const handleSingleToggle = (val) => () => { const currentIdx = chk.indexOf(val); const latestChecked = [...chk]; if (currentIdx === -1) { latestChecked.push(val); } else { latestChecked.splice(currentIdx, 1); } setChk(latestChecked); }; const chkNo = (items) => intersection(chk, items).length; const handleMultipleToggle = (i) => () => { if (chkNo(i) === i.length) { setChk(not(chk, i)); } else { setChk(union(chk, i)); } }; const pushRight = () => { setRightItems(rightItems.concat(chkLeftChecked)); setLftItems(not(lftItems, chkLeftChecked)); setChk(not(chk, chkLeftChecked)); }; const pushLeft = () => { setLftItems(lftItems.concat(chkRightChecked)); setRightItems(not(rightItems, chkRightChecked)); setChk(not(chk, chkRightChecked)); }; const ListComponent = (listItemName, ListItems) => ( <Card sx={{ p: 3 }}> <CardHeader sx={{ p: 2 }} avatar={ <Checkbox onClick={handleMultipleToggle(ListItems)} checked={chkNo(ListItems) === ListItems.length && ListItems.length !== 0} indeterminate={ chkNo(ListItems) !== ListItems.length && chkNo(ListItems) !== 0 } disabled={ListItems.length === 0} /> } title={listItemName} subheader={`${chkNo(ListItems)}/${ListItems.length} selected`} /> <hr /> <List sx={{overflow: 'auto',}}> {ListItems.map((value) => { const labelId = `transfer-list-all-item-${value}-label`; return ( <ListItem key={value} onClick={handleSingleToggle(value)} > <ListItemIcon> <Checkbox checked={chk.indexOf(value) !== -1} tabIndex={-1} disableRipple /> </ListItemIcon> <ListItemText id={labelId} primary={value} /> </ListItem> ); })} </List> </Card> ); return ( <div style={{ padding: 40, display: 'flex', flexDirection: 'column', gap: 20, backgroundColor: 'lightcyan' }}> <Stack direction="row" container spacing={5}> <Stack item>{ListComponent('Select from below', lftItems)}</Stack> <Stack item> <Stack container direction="column" sx={{ gap: 5 }} alignItems="center"> <Button variant="contained" color="info" onClick={pushRight} disabled={chkLeftChecked.length === 0} > > </Button> <Button variant="contained" color="info" onClick={pushLeft} disabled={chkRightChecked.length === 0} > < </Button> </Stack> </Stack> <Stack item>{ListComponent('Selected', rightItems)}</Stack> </Stack> </div> ); }; export default App;
輸出

示例
在此示例中,我們建立了一個自定義的增強型傳輸列表,當用戶選擇任何要傳輸的專案時,複選框將被啟用。在這裡,列表項使用不同的顏色進行自定義。
import React, { useState } from "react"; import { Stack, Checkbox, ListItem, ListItemText, Button } from "@mui/material"; const App = () => { const [lftItems, setLftItems] = useState([1, 2, 3]); const [rytItems, setRytItems] = useState([4, 5, 6]); const [chosenLftItems, setChosenLftItems] = useState([]); const [chosenRytItems, setChosenRytItems] = useState([]); const handlePush = () => { setRytItems((before) => [...before, ...chosenLftItems]); setLftItems((prevItems) => prevItems.filter((_, index) => !chosenLftItems.includes(index)) ); setChosenLftItems([]); }; const handlePull = () => { setLftItems((before) => [...before, ...chosenRytItems]); setRytItems((prevItems) => prevItems.filter((_, index) => !chosenRytItems.includes(index)) ); setChosenRytItems([]); }; const selectLftItem = (i) => { if (chosenLftItems.includes(i)) { setChosenLftItems((beforeSelected) => beforeSelected.filter((item) => item !== i) ); } else { setChosenLftItems((beforeSelected) => [...beforeSelected, i]); } }; const selectRightItem = (i) => { if (chosenRytItems.includes(i)) { setChosenRytItems((beforeSelected) => beforeSelected.filter((item) => item !== i) ); } else { setChosenRytItems((beforeSelected) => [...beforeSelected, i]); } }; return ( <div style={{ padding: 40, display: "flex", flexDirection: "column", gap: 20, backgroundColor: "lightcyan" }}> <Stack direction="row" container spacing={5}> <Stack sx={{ gap: 2 }}> {lftItems.map((item, index) => ( <ListItem key={index} onClick={() => selectLftItem(index)} sx={{ backgroundColor: "lightblue", borderRadius: 1, cursor: "pointer" }}> <Checkbox checked={chosenLftItems.includes(index)} color="primary" /> <ListItemText primary={item} /> </ListItem> ))} </Stack> <Stack item> <Stack container justifyContent="center" direction="column" sx={{ gap: 3 }} alignItems="center" > <Button variant="contained" color="info" onClick={handlePush} disabled={chosenLftItems.length === 0} > > </Button> <Button variant="contained" color="info" onClick={handlePull} disabled={chosenRytItems.length === 0} > < </Button> </Stack> </Stack> <Stack sx={{ gap: 2 }}> {rytItems.map((item, index) => ( <ListItem key={index} onClick={() => selectRightItem(index)} sx={{ backgroundColor: "lightblue", borderRadius: 1, cursor: "pointer" }} > <Checkbox checked={chosenRytItems.includes(index)} color="primary" /> <ListItemText primary={item} /> </ListItem> ))} </Stack> </Stack> </div> ); }; export default App;
輸出

結論
本文討論了在 React MUI 中建立增強型傳輸列表的完整細節。在本文中,我們學習了建立增強型傳輸列表的完整步驟,以及使用不同方法的不同示例。