Material UI Transfer List 使用详解

person smartzeng   watch_later 2024-10-01 08:41:53
visibility 192    class Transfer List    bookmark 专栏

Material UI 的 Transfer List 组件(双列表选择器)是一种非常实用的 UI 组件,允许用户在两个列表之间进行选择和转移项目。这种组件通常用于需要从一组选项中进行多项选择的场景,比如用户权限管理、标签选择等。本文将详细介绍 Transfer List 的使用,包括组件的基本用法、所有属性和方法的详细解释,以及与其他组件的结合示例。

1. Transfer List 的基本用法

1.1 安装 Material UI

首先,确保您已经安装了 Material UI。如果还没有,可以通过以下命令进行安装:

npm install @mui/material @emotion/react @emotion/styled

1.2 Transfer List 基础示例

下面是一个简单的 Transfer List 示例,展示了如何使用该组件。

import React, { useState } from 'react';
import {
  Box,
  Button,
  List,
  ListItem,
  ListItemText,
  Typography,
  Divider
} from '@mui/material';

const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grape'];

const TransferList = () => {
  const [left, setLeft] = useState(items);
  const [right, setRight] = useState([]);

  const handleToggle = (item) => {
    const currentIndex = left.indexOf(item);
    const newLeft = [...left];
    const newRight = [...right];

    if (currentIndex > -1) {
      newLeft.splice(currentIndex, 1);
      newRight.push(item);
    } else {
      const rightIndex = newRight.indexOf(item);
      newRight.splice(rightIndex, 1);
      newLeft.push(item);
    }

    setLeft(newLeft);
    setRight(newRight);
  };

  return (
    <Box display="flex" justifyContent="center" alignItems="center" height="100vh">
      <Box>
        <Typography variant="h6">可选项目</Typography>
        <List>
          {left.map((item) => (
            <ListItem button key={item} onClick={() => handleToggle(item)}>
              <ListItemText primary={item} />
            </ListItem>
          ))}
        </List>
        <Button variant="contained" onClick={() => setRight([...right, ...left])}>
          移动所有
        </Button>
      </Box>
      <Divider orientation="vertical" flexItem />
      <Box>
        <Typography variant="h6">已选项目</Typography>
        <List>
          {right.map((item) => (
            <ListItem button key={item} onClick={() => handleToggle(item)}>
              <ListItemText primary={item} />
            </ListItem>
          ))}
        </List>
        <Button variant="contained" onClick={() => setLeft([...left, ...right])}>
          移动所有
        </Button>
      </Box>
    </Box>
  );
};

export default TransferList;

代码解析

  • useState: 用于管理左侧和右侧列表的状态。
  • handleToggle: 处理项目的转移逻辑。
  • ListListItem: 用于展示可选和已选项目的列表。
  • Button: 提供移动选中项目的功能。

2. Transfer List 属性与方法

2.1 主要属性

  • items: 显示在 Transfer List 中的项目数组。
  • left: 当前可选项目列表的状态。
  • right: 当前已选项目列表的状态。
  • onToggle: 自定义转移项目的回调函数。

2.2 主要方法

  • handleToggle(item): 切换项目的选中状态。
  • setLeft(items): 更新左侧列表的项目。
  • setRight(items): 更新右侧列表的项目。

3. 结合其他组件使用

3.1 结合 Dialog 组件

将 Transfer List 嵌入到 Dialog 中,方便用户在模态框中进行选择。

import React, { useState } from 'react';
import {
  Box,
  Button,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  List,
  ListItem,
  ListItemText,
  Typography,
  Divider,
  TextField
} from '@mui/material';

const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grape'];

const TransferListDialog = () => {
  const [open, setOpen] = useState(false);
  const [left, setLeft] = useState(items);
  const [right, setRight] = useState([]);
  const [search, setSearch] = useState('');

  const handleToggle = (item) => {
    const currentIndex = left.indexOf(item);
    const newLeft = [...left];
    const newRight = [...right];

    if (currentIndex > -1) {
      newLeft.splice(currentIndex, 1);
      newRight.push(item);
    } else {
      const rightIndex = newRight.indexOf(item);
      newRight.splice(rightIndex, 1);
      newLeft.push(item);
    }

    setLeft(newLeft);
    setRight(newRight);
  };

  const filteredLeft = left.filter(item => item.toLowerCase().includes(search.toLowerCase()));

  return (
    <div>
      <Button variant="outlined" onClick={() => setOpen(true)}>打开选择</Button>
      <Dialog open={open} onClose={() => setOpen(false)}>
        <DialogTitle>选择项目</DialogTitle>
        <DialogContent>
          <Box display="flex" justifyContent="space-between">
            <Box>
              <Typography variant="h6">可选项目</Typography>
              <TextField
                variant="outlined"
                placeholder="搜索..."
                onChange={(e) => setSearch(e.target.value)}
                sx={{ mb: 2 }}
              />
              <List>
                {filteredLeft.map((item) => (
                  <ListItem button key={item} onClick={() => handleToggle(item)}>
                    <ListItemText primary={item} />
                  </ListItem>
                ))}
              </List>
              <Button variant="contained" onClick={() => setRight([...right, ...left])}>
                移动所有
              </Button>
            </Box>
            <Divider orientation="vertical" flexItem />
            <Box>
              <Typography variant="h6">已选项目</Typography>
              <List>
                {right.map((item) => (
                  <ListItem button key={item} onClick={() => handleToggle(item)}>
                    <ListItemText primary={item} />
                  </ListItem>
                ))}
              </List>
              <Button variant="contained" onClick={() => setLeft([...left, ...right])}>
                移动所有
              </Button>
            </Box>
          </Box>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setOpen(false)}>取消</Button>
          <Button onClick={() => setOpen(false)} color="primary">确认</Button>
        </DialogActions>
      </Dialog>
    </div>
  );
};

export default TransferListDialog;

代码解析

  • Dialog: 用于创建模态框,允许用户在打开对话框时进行选择。
  • DialogTitle, DialogContent, DialogActions: 分别表示对话框的标题、内容和操作按钮。

3.2 结合 Grid 组件

使用 Grid 组件来布局 Transfer List,使其更灵活。

import React, { useState } from 'react';
import {
  Box,
  Button,
  Grid,
  List,
  ListItem,
  ListItemText,
  Typography,
  Divider,
  TextField
} from '@mui/material';

const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grape'];

const GridTransferList = () => {
  const [left, setLeft] = useState(items);
  const [right, setRight] = useState([]);
  const [search, setSearch] = useState('');

  const handleToggle = (item) => {
    const currentIndex = left.indexOf(item);
    const newLeft = [...left];
    const newRight = [...right];

    if (currentIndex > -1) {
      newLeft.splice(currentIndex, 1);
      newRight.push(item);
    } else {
      const rightIndex = newRight.indexOf(item);
      newRight.splice(rightIndex, 1);
      newLeft.push(item);
    }

    setLeft(newLeft);
    setRight(newRight);
  };

  const filteredLeft = left.filter(item => item.toLowerCase().includes(search.toLowerCase()));

  return (
    <Grid container spacing={2} justifyContent="center" alignItems="center" height="100vh">
      <Grid item>
        <Typography variant="h6">可选项目</Typography>
        <TextField
          variant="outlined"
          placeholder="搜索..."
          onChange={(e) => setSearch(e.target.value)}
          sx={{ mb: 2 }}
        />
        <List>
          {filteredLeft.map((item) => (
            <ListItem button key={item} onClick={() => handleToggle(item)}>
              <ListItemText primary={item} />
            </ListItem>
          ))}
        </List>
        <Button variant="contained" on

Click={() => setRight([...right, ...left])}>
          移动所有
        </Button>
      </Grid>
      <Divider orientation="vertical" flexItem />
      <Grid item>
        <Typography variant="h6">已选项目</Typography>
        <List>
          {right.map((item) => (
            <ListItem button key={item} onClick={() => handleToggle(item)}>
              <ListItemText primary={item} />
            </ListItem>
          ))}
        </List>
        <Button variant="contained" onClick={() => setLeft([...left, ...right])}>
          移动所有
        </Button>
      </Grid>
    </Grid>
  );
};

export default GridTransferList;

代码解析

  • 使用 Grid 组件来排列左侧和右侧列表。
  • 依然保持原有的项目转移逻辑。

4. 小结

本文详细探讨了 Material UI Transfer List 组件的使用,涵盖了基本用法、所有属性和方法,以及与 Dialog、Grid 等其他组件的结合示例。通过这些示例,您可以清晰地了解如何在项目中实现 Transfer List,并根据需要进行自定义。

希望这篇文章能帮助您更好地理解和使用 Material UI 的 Transfer List 组件。如果您有任何问题或需要进一步的帮助,请随时与我交流!

chat评论区
评论列表
menu