首页 > 解决方案 > 自动调整大小并将项目拖动到面板中

问题描述

我想使用以下布局实现放置项目的面板:

在此处输入图像描述

我尝试了以下代码:

import React, { useCallback, useEffect } from "react";
import { Box, Grid, Tab, Tabs, Typography } from "@material-ui/core";
import { makeStyles, Theme } from "@material-ui/core/styles";
import { sizing } from "@material-ui/system";

const useStyles1 = makeStyles((theme: Theme) => ({
    color: {
        backgroundColor: "green",
        border: "1px solid black"
    }
}));

const useStyles2 = makeStyles((theme: Theme) => ({
    color: {
        backgroundColor: "mediumvioletred",
        border: "1px solid black"
    }
}));

const useStyles3 = makeStyles((theme: Theme) => ({
    color: {
        backgroundColor: "orange",
        border: "1px solid black"
    }
}));

export default function Hello() {
    const classes1 = useStyles1();
    const classes2 = useStyles2();
    const classes3 = useStyles3();

    return (
        <>
            <Grid
                spacing={0}
                container
                direction="row"
                justifyContent="flex-start"
                xs={12}
                alignItems={"stretch"}
                style={{ height: "100vh", overflow: "auto", flexGrow: 1 }}
            >
                <Grid
                    // spacing={0}
                    // container
                    // direction="row"
                    // xs={3}
                    //  style={{ height: "100%", overflow: "auto" }}
                >
                    <Grid item xs={12}>
                        <Grid
                            className={classes1.color}
                            container
                            direction="column"
                            justifyContent="flex-start"
                            alignItems="center"
                        >
                            <Grid item xs={12}>
                                <Box m={2}>item link 1</Box>
                            </Grid>
                            <Grid item xs={12}>
                                <Box m={2}>item link 2</Box>
                            </Grid>
                            <Grid item xs={12}>
                                <Box m={2}>item link 3</Box>
                            </Grid>
                            <Grid item xs={12}>
                                <Box m={2}>item link 4</Box>
                            </Grid>
                        </Grid>
                    </Grid>
                </Grid>

                <Grid
                    spacing={0}
                    container
                    direction="row"
                    xs={2}
                    className={classes2.color}
                    style={{ height: "100%", overflow: "auto" }}
                >
                    <Grid item xs={12}>
                        <Box m={10}>item 11</Box>
                    </Grid>
                    <Grid item xs={12}>
                        <Box m={10}>item 11</Box>
                    </Grid>
                    <Grid item xs={12}>
                        <Box m={10}>item 13</Box>
                    </Grid>
                    <Grid item xs={12}>
                        <Box m={10}>item 14</Box>
                    </Grid>
                    <Grid item xs={12}>
                        <Box m={10}>item 15</Box>
                    </Grid>
                    <Grid item xs={12}>
                        <Box m={10}>item 16</Box>
                    </Grid>
                </Grid>
                <Grid
                    container
                    direction="row"
                    xs={4}
                    alignItems={"stretch"}
                    style={{ height: "100%", overflow: "auto" }}
                >
                    <Grid item xs={12}>
                        <Grid
                            className={classes3.color}
                            container
                            direction="row"
                            justifyContent="space-around"
                            alignItems="center"
                            style={{ width: "100%", overflow: "auto" }}
                        >
                            <Grid item xs={12}>
                                <Box m={2}>item area 1</Box>
                            </Grid>
                            <Grid item xs={12}>
                                <Box m={2}>item area 2</Box>
                            </Grid>
                        </Grid>
                    </Grid>
                </Grid>
            </Grid>
        </>
    );
}

完整代码:https ://stackblitz.com/edit/react-ts-k6hpuf?file=Hello.tsx

你知道我如何使用打字稿实现边框的拖动和正确的布局吗?

标签: cssreactjsreact-typescriptreact-material

解决方案


这是一个使用Material UI 和react-beautiful-dnd

使用基于票证系统(如 Jira)的拖放

应用程序.js

import React, { useState } from "react";
import makeStyles from "@material-ui/core/styles/makeStyles";
import Grid from "@material-ui/core/Grid";
import { DragDropContext } from "react-beautiful-dnd";
import Column from "./Column";

const App = () => {
  function range(start, end) {
    return Array(end - start + 1)
      .fill()
      .map((_, idx) => start + idx);
  }

  const initialColumns = {
    links: {
      id: "links",
      list: [
        { id: "1", text: "text1" },
        { id: "2", text: "text2" },
        { id: "3", text: "text3" }
      ]
    },
    items: {
      id: "items",
      list: []
    },
    area1: {
      id: "area1",
      list: []
    },
    area2: {
      id: "area2",
      list: [
        { id: "7", text: "text7" },
        { id: "8", text: "text8" },
        { id: "9", text: "text9" }
      ]
    }
  };

  range(4, 25).forEach((idx) => {
    initialColumns.area1.list.push({
      id: idx.toString(),
      text: "text" + idx.toString()
    });
  });

  range(24, 60).forEach((idx) => {
    initialColumns.items.list.push({
      id: idx.toString(),
      text: "text" + idx.toString()
    });
  });

  const [columns, setColumns] = useState(initialColumns);

  const onDragEnd = ({ source, destination }) => {
    // Make sure we have a valid destination
    if (destination === undefined || destination === null) return null;

    // Make sure we're actually moving the item
    if (
      source.droppableId === destination.droppableId &&
      destination.index === source.index
    )
      return null;

    // Set start and end variables
    const start = columns[source.droppableId];
    const end = columns[destination.droppableId];

    // If start is the same as end, we're in the same column
    if (start === end) {
      // Move the item within the list
      // Start by making a new list without the dragged item
      console.log(start);
      const newList = start.list.filter((_, idx) => idx !== source.index);

      // Then insert the item at the right location
      newList.splice(destination.index, 0, start.list[source.index]);

      // Then create a new copy of the column object
      const newCol = {
        id: start.id,
        list: newList
      };

      // Update the state
      setColumns((state) => ({ ...state, [newCol.id]: newCol }));
      return null;
    } else {
      // If start is different from end, we need to update multiple columns
      // Filter the start list like before
      const newStartList = start.list.filter((_, idx) => idx !== source.index);

      // Create a new start column
      const newStartCol = {
        id: start.id,
        list: newStartList
      };

      // Make a new end list array
      const newEndList = end.list;

      // Insert the item into the end list
      newEndList.splice(destination.index, 0, start.list[source.index]);

      // Create a new end column
      const newEndCol = {
        id: end.id,
        list: newEndList
      };

      // Update the state
      setColumns((state) => ({
        ...state,
        [newStartCol.id]: newStartCol,
        [newEndCol.id]: newEndCol
      }));
      return null;
    }
  };

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Grid
        container
        direction="row"
        justifyContent="space-around"
        alignItems="stretch"
      >
        <Grid item xs={1}>
          <Column
            isLinks={true}
            backgroundColor={"lightgreen"}
            height={"90vh"}
            width={"100%"}
            column={columns.links}
            key={columns.links.id}
          />
        </Grid>
        <Grid item xs={1}>
          <Column
            backgroundColor={"salmon"}
            height={"90vh"}
            width={"100%"}
            column={columns.items}
            key={columns.items.id}
          />
        </Grid>
        <Grid item xs={9}>
          <Column
            className={"flex-col-scroll"}
            height={"42vh"}
            width={"100%"}
            backgroundColor={"darkorange"}
            column={columns.area1}
            key={columns.area1.id}
          />
          <Column
            className={"flex-col-scroll"}
            height={"42vh"}
            width={"100%"}
            backgroundColor={"darkorange"}
            column={columns.area2}
            key={columns.area2.id}
          />
        </Grid>
      </Grid>
    </DragDropContext>
  );
};

export default App;

const useStyles = makeStyles((theme) => ({}));

列.js

import React from "react";
import { Droppable } from "react-beautiful-dnd";
import RootRef from "@material-ui/core/RootRef";
import List from "@material-ui/core/List";
import ListItemCustom from "./ListItemCustom";
import Typography from "@material-ui/core/Typography";

const Column = ({ isLinks, height, width, backgroundColor, column }) => {
  const linksStyle = !isLinks
    ? {
        maxHeight: "85%",
        overflow: "auto"
      }
    : {};

  return (
    <div
      style={{
        height: height,
        width: width,
        backgroundColor: backgroundColor,
        margin: 10,
        padding: 20,
        color: "white"
      }}
    >
      <Typography variant={"h4"}>{column.id}</Typography>
      <Droppable droppableId={column.id}>
        {(provided) => (
          <RootRef rootRef={provided.innerRef}>
            <List style={linksStyle}>
              {column.list.map((itemObject, index) => {
                return <ListItemCustom index={index} itemObject={itemObject} />;
              })}
              {provided.placeholder}
            </List>
          </RootRef>
        )}
      </Droppable>
    </div>
  );
};

export default Column;

ListItemCustom.js

import React from "react";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
import IconButton from "@material-ui/core/IconButton";
import { Draggable } from "react-beautiful-dnd";

const ListItemCustom = ({ itemObject, index }) => {
  return (
    <Draggable draggableId={itemObject.id} key={itemObject.id} index={index}>
      {(provided) => (
        <ListItem
          key={itemObject.id}
          role={undefined}
          dense
          button
          ContainerComponent="li"
          ContainerProps={{ ref: provided.innerRef }}
          {...provided.draggableProps}
          {...provided.dragHandleProps}
        >
          <ListItemText
            sytles={{ fontFamily: "Quicksand" }}
            primary={`${itemObject.text}`}
          />
          <ListItemSecondaryAction>
            <IconButton
              edge="end"
              aria-label="comments"
              question-uid={itemObject.id}
            >
              {/* <DeleteIcon /> */}
            </IconButton>
          </ListItemSecondaryAction>
        </ListItem>
      )}
    </Draggable>
  );
};

export default ListItemCustom;

更新 1:添加了错误的滚动

更新 2:在架构中添加了滚动和另一个垂直侧边栏

更新 3:使用材质 UI 网格 API 重新排序布局间距

更新 4:添加主代码以防代码沙箱链接中断


推荐阅读