首页 > 解决方案 > 如何获得按钮到材料 ui 列表的末尾和复选框到列表的开头?

问题描述

我的css不是很好,我面临很多困难......我正在尝试在material-ui的帮助下制作一个react todo应用程序......我的问题是我想在material-中显示待办事项ui 列表,在列表中的位置 1) 第一项将是复选框 2) 第二个待办事项文本 3) 第三个编辑和删除按钮

在此处输入图像描述

渲染 mui 列表的代码

import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { todoDeleted, todoUpdated, todoCompleted } from '../Slices/TodoSlice';
import { Button, Checkbox, List, ListItem, ListItemSecondaryAction, ListItemText, makeStyles } from '@material-ui/core'

const useStyles = makeStyles({
  listRoot: {
    display: 'flex',
    alignItems: 'center',
    backgroundColor: '#fce4ec',
    borderWidth: "1px",
    borderColor: "#aaaaaa",
    borderStyle: "solid",
    borderRadius: "20px",
    height: "35px",
    margin: "5px 5px"
  },
  item: {
    display: 'flex',
    flexDirection: 'column',
    justifyContent: 'center',
    width: "500px"
  }
})

export default function TodoItem({ todo, i }) {
  const classes = useStyles()
  const dispatch = useDispatch();
  const [edit, setEdit] = useState(false);
  const [text, setText] = useState(todo.text);

  const handleUpdate = () => {
    dispatch(
      todoUpdated({
        id: todo.id,
        text,
      })
    );

    if (edit) {
      setText(todo.text);
    }
    setEdit(!edit);
  };

  return (
      <div className={classes.listRoot}>
        <List>
          <ListItem className={classes.item}>
        
        <ListItemText>
          {todo.done ? (
            <p>
              <del>{todo.text}</del>
            </p>
          ) : (
            <h4>
              {edit ? (
                <input
                  type="text"
                  placeholder={text}
                  value={text}
                  onChange={(e) => setText(e.target.value)}
                />
              ) : (
                todo.text
              )}
            </h4>
          )}
        </ListItemText>
        <ListItemSecondaryAction>
        <Checkbox
          value={todo.id}
          onChange={(e) => dispatch(todoCompleted(+e.target.value))}
          defaultChecked={todo.done}
        />
        <button
          variant="contained" color="primary" edge='end'
          onClick={() => handleUpdate()}
          disabled={todo.done}
        >
          {edit ? 'Update' : 'Edit'}
        </button>
        <button
          variant="contained" color="primary"
          onClick={() => dispatch(todoDeleted(todo.id))}
        >
          Delete
        </button>
        </ListItemSecondaryAction>
        </ListItem>
        </List>
      </div>
  );
}

我想要第一项作为复选框,第二个待办事项文本和第三个按钮,请指导我

标签: javascriptreactjsmaterial-ui

解决方案


这是您编辑的 CopePen,这是我修改的主要代码:

TodoList.js:

import { makeStyles, List } from "@material-ui/core";
import React from "react";
import { useSelector } from "react-redux";
import TodoItem from "./TodoItem";

const useStyles = makeStyles({
  rootDiv: {
    display: "flex",
    flexDirection: "column",
    justifyContent: "center",
    marginLeft: "10px",
    marginRight: "10px"
  },
  p: {
    fontSize: "30px",
    fontweight: "bolder"
  }
});

export default function TodoList() {
  const classes = useStyles();
  const todos = useSelector((state) => state.TodoReducer);
  const filter = useSelector((state) => state.viewFilterReducer);

  const getVisibleTodos = (todos, filter) => {
    switch (filter) {
      case "SHOW_ALL":
        return todos;
      case "SHOW_ACTIVE":
        return todos.filter((todo) => !todo.done);
      case "SHOW_COMPLETED":
        return todos.filter((todo) => todo.done);
      default:
        return todos;
    }
  };
  const visibleTodos = getVisibleTodos(todos, filter);

  return (
    <div className={classes.rootDiv}>
      {visibleTodos?.length === 0 ? (
        <p className={classes.p}>No Todo Item Here</p>
      ) : (
        <List>
          {/*
            I moved the list here, because you need to create only one list 
            and loop over you items  
          */}
          {visibleTodos.map((todo, i) => (
            <TodoItem key={i} todo={todo} />
          ))}
        </List>
      )}
    </div>
  );
}

TodoItem.js:

import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { todoDeleted, todoUpdated, todoCompleted } from "../Slices/TodoSlice";
import {
  Button,
  Checkbox,
  List,
  ListItem,
  ListItemSecondaryAction,
  ListItemText,
  ListItemIcon,
  makeStyles
} from "@material-ui/core";

/* 
Since we fixed the issue about displaying multiple <List>,
you only need to style the items.
You can now properly define the height of your items, and set whatever you want as style,
the default flex layout is kept
*/
const useStyles = makeStyles({
  item: {
    height: "35px",
    alignItems: "center",
    backgroundColor: "#fce4ec",
    border: "1px solid #aaaaaa",
    borderRadius: "20px",
    margin: "5px 5px"
  }
});

export default function TodoItem({ todo, i }) {
  const classes = useStyles();
  const dispatch = useDispatch();
  const [edit, setEdit] = useState(false);
  const [text, setText] = useState(todo.text);

  const handleUpdate = () => {
    dispatch(
      todoUpdated({
        id: todo.id,
        text
      })
    );

    if (edit) {
      setText(todo.text);
    }
    setEdit(!edit);
  };

  return (
    <ListItem className={classes.item}>
      <Checkbox
        value={todo.id}
        onChange={(e) => dispatch(todoCompleted(+e.target.value))}
        defaultChecked={todo.done}
      />
      <ListItemText>
        {todo.done ? (
          <p>
            <del>{todo.text}</del>
          </p>
        ) : (
          <h4>
            {edit ? (
              <input
                type="text"
                placeholder={text}
                value={text}
                onChange={(e) => setText(e.target.value)}
              />
            ) : (
              todo.text
            )}
          </h4>
        )}
      </ListItemText>
      <ListItemSecondaryAction>
        <button
          variant="contained"
          color="primary"
          edge="end"
          onClick={() => handleUpdate()}
          disabled={todo.done}
        >
          {edit ? "Update" : "Edit"}
        </button>
        <button
          variant="contained"
          color="primary"
          onClick={() => dispatch(todoDeleted(todo.id))}
        >
          Delete
        </button>
      </ListItemSecondaryAction>
    </ListItem>
  );
}

我主要改变了以下几点:

  1. 移动<List>了父组件中的组件。您正在为每个项目创建一个列表,这会产生多个 CSS 问题。注意你的组件应该显示什么!
  2. 也删除了 CSSlistRootdiv节点。不再需要它了
  3. 将复选框移动为 listItem 的第一个子项,因此它尊重您要求的顺序

布局有自己的填充值。我只能强烈建议您保持原样,因为它很干净,但是如果您真的想将您的项目内容居中,您仍然可以为您的列表项目和第二个元素添加填充,例如:

const useStyles = makeStyles({
  item: {
    // ...
  },
  itemSpacing: { padding: 0 25% }
});

进而:

<ListItem className={[classes.item, classes.itemSpacing]}>

和 :

<ListItemSecondaryAction className={classes.itemSpacing}>

但是要非常小心,如果您的项目文本太长,它会中断,1)因为您为项目设置了硬编码高度,以及 2)因为ListItemSecondaryActionposition: absolute


推荐阅读