材质UI缩放动画,然后删除

时间:2018-11-06 16:35:10

标签: javascript reactjs material-ui

我正在创建一个动态界面,用户可以在其中添加和删除动态数量的项目。有一个添加按钮,每个项目都有一个删除按钮。我将Zoom中包含的每个项目都赋予了一些动画效果。添加新项目时,此方法效果很好。删除项目时遇到问题,因为它从DOM中取消了项目,动画丢失了。在过渡上是否存在某种回调,可用于在动画化之后更新包含项的数组?还是更好的解决方案?

我概述了实现此目的的两种可能尝试,但都带有问题。第一次尝试使我的项目在删除时没有动画,而第二次尝试使我在它们曾经存在的地方留有空隙(请注意:网格是我设计中的理想组成部分)

代码沙箱:https://codesandbox.io/s/l2lly078kq

import React from "react";
import Typography from "@material-ui/core/Typography";
import Button from "@material-ui/core/Button";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import Zoom from "@material-ui/core/Zoom/Zoom";

let itemCount = 0;

export default class extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      items: [],
      items2: [],
      hiddenItems: []
    };
  }

  handleAddItem = () => {
    let items = this.state.items;
    items.push(`Item ${itemCount++}`);
    this.setState({ items });
  };

  handleDeleteItem = index => {
    let items = this.state.items;
    items.splice(index, 1);
    this.setState({ items });
  };

  handleAddItem2 = () => {
    let items2 = this.state.items2;
    items2.push(`Item ${itemCount++}`);
    this.setState({ items2 });
  };

  handleDeleteItem2 = index => {
    let hiddenItems = this.state.hiddenItems;
    hiddenItems.push(index);
    this.setState({ hiddenItems });
  };

  render() {
    const { items, items2, hiddenItems } = this.state;

    return (
      <React.Fragment>
        <Typography>
          Items animate in, but instantly are removed instead of animating out
        </Typography>
        <Button onClick={this.handleAddItem}>Add</Button>
        <Grid container spacing={16}>
          {items.map((item, index) => (
            <Zoom in={true}>
              <Grid item xs={3}>
                <Paper>
                  <Button onClick={() => this.handleDeleteItem(index)}>
                    Delete
                  </Button>
                  {item}
                </Paper>
              </Grid>
            </Zoom>
          ))}
        </Grid>
        <br />
        <br />
        <Typography>
          Items animate in and out, but the grid does not collapse
        </Typography>
        <Button onClick={this.handleAddItem2}>Add</Button>
        <Grid container spacing={16}>
          {items2.map((item, index) => (
            <Zoom in={!hiddenItems.includes(index)}>
              <Grid item xs={3}>
                <Paper>
                  <Button onClick={() => this.handleDeleteItem2(index)}>
                    Delete
                  </Button>
                  {item}
                </Paper>
              </Grid>
            </Zoom>
          ))}
        </Grid>
      </React.Fragment>
    );
  }
}

enter image description here

3 个答案:

答案 0 :(得分:2)

尝试以下链接

enter link description here

我已将您的代码更改如下

import React from "react";
import Typography from "@material-ui/core/Typography";
import Button from "@material-ui/core/Button";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import Zoom from "@material-ui/core/Zoom/Zoom";

let itemCount = 0;

export default class extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      items: [],
      items2: [],
      hiddenItems: [],
      hiddenItems2: []
    };
  }

  handleAddItem = () => {
    let items = this.state.items;
    items.push(`Item ${itemCount++}`);
    this.setState({ items });
  };

  handleDeleteItem = index => {
    let hiddenItems = this.state.hiddenItems;
    hiddenItems.push(index);
    this.setState({ hiddenItems });

    // let items = this.state.items;
    // items.splice(index, 1);
    // this.setState({ items });
  };

  handleAddItem2 = () => {
    let items2 = this.state.items2;
    items2.push(`Item ${itemCount++}`);
    this.setState({ items2 });
  };

  handleDeleteItem2 = index => {
    let hiddenItems2 = this.state.hiddenItems2;
    hiddenItems2.push(index);
    this.setState({ hiddenItems2 });
  };

  render() {
    const { items, items2, hiddenItems, hiddenItems2 } = this.state;

    if (hiddenItems.length > 0) {
      console.log(hiddenItems);

      setTimeout(() => {
        let items = this.state.items;
        for (var item of hiddenItems) {
          items.splice(item, 1);
        }

        this.setState({ hiddenItems: [], items });
      }, 250);
    }

    return (
      <React.Fragment>
        <Typography>
          Items animate in, but instantly are removed instead of animating out
        </Typography>
        <Button onClick={this.handleAddItem}>Add</Button>
        <Grid container spacing={16}>
          {items.map((item, index) => (
            <Zoom in={!hiddenItems.includes(index)}>
              <Grid item xs={3}>
                <Paper>
                  <Button onClick={() => this.handleDeleteItem(index)}>
                    Delete
                  </Button>
                  {item}
                </Paper>
              </Grid>
            </Zoom>
          ))}
        </Grid>
        <br />
        <br />
        <Typography>
          Items animate in and out, but the grid does not collapse
        </Typography>
        <Button onClick={this.handleAddItem2}>Add</Button>
        <Grid container spacing={16}>
          {items2.map((item, index) => (
            <Zoom in={!hiddenItems2.includes(index)}>
              <Grid item xs={3}>
                <Paper>
                  <Button onClick={() => this.handleDeleteItem2(index)}>
                    Delete
                  </Button>
                  {item}
                </Paper>
              </Grid>
            </Zoom>
          ))}
        </Grid>
      </React.Fragment>
    );
  }
}

答案 1 :(得分:1)

您可以使用onExited组件的Zoom回调(material-ui过渡基于react过渡组Transition-请参见此处http://reactcommunity.org/react-transition-group/transition#Transition-prop-onExited的文档)道具来删除该项目缩放过渡完成后,从项目数组中单击鼠标左键,开始过渡。例如:

<Zoom
    in={this.state.deletedItem !== item}
    onExited={() => this.handleDeleteItem(item)}
>

<Button onClick={() => this.handleRemoveItem(item)}>

从代码中还可以看到,

  • 删除了hiddenItems数组,仅存储要删除的当前项目-in={this.state.deletedItem !== item}

您可以在这里查看我的版本:https://codesandbox.io/s/heuristic-booth-fnwwk

此方法还允许您在删除失败(例如,在删除时调用API)的情况下取消转换,因为转换和删除事件是分开的。有关示例https://codesandbox.io/s/flamboyant-babbage-y506f,请参见以下代码。

答案 2 :(得分:0)

已在Material UI Zoom Api中提供了指向Transition props的链接。在他们尝试"unmountOnExit"道具时,

  

默认情况下,子组件在达到“退出”状态后仍保持挂载状态。如果您希望在组件退出完成后卸载该组件,请设置unmountOnExit。

此道具在official examples中配合缩放使用