简体   繁体   English

Reactjs - 同位素 - 点击展开和折叠 - 但一次只有一项

[英]Reactjs - Isotope - expand and collapse on click - but have ONLY one item at a time

I am working on an isotope application - and I want to smooth this application so that onclick an item expands -- but on clicking another item - it closes the last -- here is the code base - what is the best way of handling this.我正在处理一个同位素应用程序 - 我想平滑这个应用程序,以便 onclick 一个项目展开 - 但在单击另一个项目时 - 它会关闭最后一个 - 这是代码库 - 处理这个问题的最佳方法是什么。 My problem at the moment is its possible to open up multiple cells at once - and I haven't worked out the logic to collapse non-active items.我目前的问题是可以一次打开多个单元格——而且我还没有弄清楚折叠非活动项目的逻辑。

在此处输入图像描述

https://codesandbox.io/s/brave-sea-tnih7?file=/src/IsotopePopClickEl.js https://codesandbox.io/s/brave-sea-tnih7?file=/src/IsotopePopClickEl.js

IsotopePopClickEl. IsotopePopClickEl。

import React, { Component } from "react";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
//import Rating from '@material-ui/lab/Rating';

//import parse from 'html-react-parser';

import "./IsotopePopClickEl.css";

class IsotopePopClickEl extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = { expanded: false };
    this.onClick = this.onClick.bind(this);
  }

  expand() {
    this.setState({
      expanded: true
    });
  }

  collapse(event) {
    this.setState({
      expanded: false
    });
  }

  onClick() {
    if (this.state.expanded) {
      this.collapse();
    } else {
      this.expand();
    }
  }

  render() {
    return (
      <div
        className={
          "isotope-pop-click " +
          (this.state.expanded ? "is-expanded" : "is-collapsed")
        }
        onClick={this.onClick}
      >
        <div className="frontFace">
          <Grid container spacing={0}>
            <Grid item xs={12} sm={12}>
              <div className="image-wrapper">
                <img
                  className="image-item"
                  src={this.props.item.image}
                  alt=""
                />
              </div>
              <h3>{this.props.item.label}</h3>
            </Grid>
          </Grid>
        </div>

        <div className="backFace">
          <Grid container spacing={0}>
            <Grid item xs={12} sm={5}>
              <div className="image-wrapper">
                <img
                  className="image-item"
                  src={this.props.item.image}
                  alt=""
                />
              </div>
            </Grid>
            <Grid item xs={12} sm={7}>
              <h3>{this.props.item.label}</h3>
              <div>
                <p>some body text text text text</p>
              </div>
              <div>
                <Button variant="contained" color="primary">
                  Read more
                </Button>
              </div>
            </Grid>
          </Grid>
        </div>
      </div>
    );
  }
}

export default IsotopePopClickEl;

I wasn't sure what is the easier way to handle this -- if its a case of pushing back an active item record into the parent shell IsotopeWrapper - and if a new click is picked up to close all other IsotopePopClickEl's --我不确定处理这个问题的更简单方法是什么——如果是将活动项目记录推回父 shell IsotopeWrapper——并且如果选择新的点击以关闭所有其他 IsotopePopClickEl——

I have to make bunch of changed to your codesandbox as there are few issues with existing code.我必须对您的 codesandbox 进行大量更改,因为现有代码几乎没有问题。 Updated and working codesandbox can be found here .可以在此处找到更新的和可用的代码和框。

Let's go through the changes I made:让我们通过我所做的更改 go:

  1. Notify parent/container as soon as item is clicked so that parent can update state of other items.单击项目后立即通知父级/容器,以便父级可以更新其他项目的 state。 To do that, I removed state from IsotopePopClickEl and moved it to IsotopeWrapper where wrapper would set selected property on each item to indicate if it is selected (or you can call it expanded.) or not.为此,我从state中删除了IsotopePopClickEl并将其移至IsotopeWrapper ,其中 wrapper 将在每个项目上设置selected属性以指示它是否被选中(或者您可以将其称为展开。)。
class IsotopePopClickEl extends Component {
  ...
  onClick() {
    this.props.onClick();
  } 

  render() {
    return (
      <div
        className={
          "isotope-pop-click " +
          (this.props.item.selected ? "is-expanded" : "is-collapsed")
        }
        onClick={this.onClick}
      >
      ...
    );
  }
}
  1. Update state (selected) of each item so that IsotopePopClickEl can determine which item to expand to:更新每个项目的 state(已选择),以便IsotopePopClickEl可以确定扩展到哪个项目:
class IsotopeWrapper extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      resultsList: [
        // items in the list
      ]
    };
  }

  onClick(item) {
    const newList = this.state.resultsList.map((i) => {
      i.selected = i === item;
      return i;
    });
    this.setState({
      resultsList: newList
    });
  }

  render() {
    let items = [
      {
        buildEntity: () => ( // <- converted entity prop to method
          <IsotopePopClickEl
            item={this.state.resultsList[0]} // <- use item from the state
            onClick={() => this.onClick(this.state.resultsList[0])} // <- attach click handler
          />
        ),
        ...
      }
    ...
  }
}
  1. Finally, not sure if you noticed but I replaced entity property on each item in IsotopeWrapper class with buildEntity function as using property would cache view after creating it for the first time and will not update after wards on new state. Update IsotopeHandler to call buildEntity .最后,不确定您是否注意到,但我用IsotopeWrapper function 替换了buildEntity class 中每个项目的entity属性,因为使用属性会在第一次创建视图后缓存视图,并且不会在新的 state 之后更新。更新IsotopeHandler以调用buildEntity
<div className="grid-item-wrapper">{item.buildEntity()}</div>

That's all!就这样!

You are doing it well for the way you mentioned where you want to be able to open multiple items at the same time.对于您提到的希望能够同时打开多个项目的方式,您做得很好。 But as you want only to open each time, you should move the state to the parent component and that state should be an identifier of the element that is currently opened by, ie, the id of the element.但是由于每次只想打开,所以应该将state移到父组件中,state应该是当前打开的元素的标识符,即元素的id。

So you should end up with something like:所以你最终应该得到这样的东西:

this.state = { expanded: "itemId" }

Your onclick method will be something like:您的 onclick 方法类似于:

onClick(e) {
  this.setState({ expanded: e.target.id }) // use the identifier that you want
}

And in each IsotopePopClickEl you just check if the id (or whatever) of the element is the same as this.state.expanded and if true, you append the class. This can be done if you map some items to that IsotopePopClickEl component or if you just copy/paste them to the same parent component (first one is a better approach obviously).在每个IsotopePopClickEl中,您只需检查元素的id (或其他)是否与this.state.expanded相同,如果为真,则您 append class。如果您 map 该IsotopePopClickEl组件的某些项目或者如果您只需将它们复制/粘贴到同一个父组件(第一个显然是更好的方法)。

In that first approach you should pass new props to IsotopePopClickEl to check that parent's state of which item is expanded在第一种方法中,您应该将新的道具传递给IsotopePopClickEl以检查父级的 state 哪个项目已expanded

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM