[英]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:
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}
>
...
);
}
}
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
/>
),
...
}
...
}
}
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.