以编程方式更改 react-grid-layout 中的 height/width 项
Programmatically change height/width of items in react-grid-layout
有没有办法以编程方式更改项目布局的 w
和 h
?用例是有一个 "collapse" 按钮,它将高度降低到恒定高度,足以离开项目的 header 。为此,我最初的想法是让 layouts
保持在组件的状态,并手动将折叠的 item/s 的高度更改为另一个恒定高度。
然而,似乎库会在初始渲染后忽略对 layout
的更改。是这种情况还是我这边的错误?如果这是正常行为,是否有另一种方法可以通过编程方式更改高度?
这是实现 react-grid-layout
的独立组件。有两个 "widgets" 有一个 "collapse" 的 onClick 处理程序。通过设置状态,它会触发 re-render 并重新计算布局,以便任何折叠的项目都具有降低的高度。控制台日志显示呈现的组件具有正确的新布局,但它没有反映在屏幕上,这让我相信还有另一个对高度的引用。
import React, { Component } from 'react';
import GridLayout, { WidthProvider } from 'react-grid-layout';
const Grid = WidthProvider(GridLayout);
// # WidgetsContainer
// Container WidgetsContainer component.
class WidgetsContainer extends Component {
static defaultProps = {
isDraggable: true,
isResizable: true,
rowHeight: 1,
cols: 12,
}
constructor(props) {
super(props);
this.state = {
layouts: [
{
i: 'item_1',
x: 0,
y: 0,
w: 5,
h: 25,
}, {
i: 'item_2',
x: 5,
y: 0,
w: 7,
h: 30,
},
],
collapsedWidgets: {},
};
}
toggleWidget(id) {
return () => {
const newState = {...this.state.collapsedWidgets};
const collapsed = typeof newState[id] === 'boolean' ? newState[id] : false;
newState[id] = !collapsed;
this.setState({
collapsedWidgets: newState,
});
}
}
onResize(layouts) {
this.setState({
layouts,
});
}
getModifiedLayouts() {
const { layouts, collapsedWidgets } = this.state;
const newLayouts = layouts.map(layout => {
const newLayout = { ...layout };
if (collapsedWidgets[newLayout.i]) {
newLayout.h = 5;
}
return newLayout;
});
return newLayouts;
}
getWidgets() {
const widgets = [{
component: <div style={{ height: '250px', background: 'lightgray' }}>Content</div>,
title: 'Item 1',
id: 'item_1',
}, {
component: <div style={{ height: '310px', background: 'lightgray' }}>Content 2</div>,
title: 'Item 2',
id: 'item_2',
}];
return widgets;
}
generateDOM() {
const widgets = this.getWidgets();
const modifiedLayouts = this.getModifiedLayouts();
return widgets.map((widget, i) => {
return (<div key={i} _grid={modifiedLayouts[i]}>
<div style={{ background: 'gray' }} onClick={::this.toggleWidget(widget.id)}>
{widget.title}
{widget.component}
</div>
</div>);
});
}
render() {
const widgets = this.generateDOM();
console.log(widgets[0].props._grid)
return (<div style={{ marginTop: '15px' }}>
{widgets ? <Grid className="layout"
{...this.props}
onResizeStop={::this.onResize}
>
{widgets}
</Grid> : null}
</div>);
}
}
export default WidgetsContainer;
事实证明,诀窍是不使用 _grid
而是在 Grid
组件上使用 layout
属性。这是一个有效的 jsfiddle:
http://jsfiddle.net/zekedroid/d9o75d24/
和代码:
const Grid = ReactGridLayout.WidthProvider(ReactGridLayout);
class Logo extends React.Component {
constructor(props) {
super(props);
this.state = {
layouts: [
{
i: '0',
x: 0,
y: 0,
w: 5,
h: 25,
}, {
i: '1',
x: 5,
y: 0,
w: 7,
h: 30,
},
],
collapsedWidgets: {},
};
}
toggleWidget(id) {
return () => {
const newState = {...this.state.collapsedWidgets};
const collapsed = typeof newState[id] === 'boolean' ? newState[id] : false;
newState[id] = !collapsed;
this.setState({
collapsedWidgets: newState,
});
}
}
onResize(layouts) {
this.setState({
layouts,
});
}
getModifiedLayouts() {
const { layouts, collapsedWidgets } = this.state;
const newLayouts = layouts.map(layout => {
const newLayout = { ...layout };
if (collapsedWidgets[newLayout.i]) {
newLayout.h = 5;
}
return newLayout;
});
return newLayouts;
}
getWidgets() {
const widgets = [{
component: <div style={{ height: '250px', background: 'lightgray' }}>Content</div>,
title: 'Item 1',
id: '0',
}, {
component: <div style={{ height: '310px', background: 'lightgray' }}>Content 2</div>,
title: 'Item 2',
id: '1',
}];
return widgets;
}
generateDOM() {
const widgets = this.getWidgets();
return widgets.map((widget, i) => {
return (<div key={i} style={{ overflowY: 'auto' }}>
<div style={{ background: 'gray' }} onClick={this.toggleWidget(widget.id).bind(this)}>
{widget.title}
{widget.component}
</div>
</div>);
});
}
render() {
const widgets = this.generateDOM();
const modifiedLayouts = this.getModifiedLayouts();
return (<div style={{ marginTop: '15px' }}>
{widgets ? <Grid className="layout"
{...this.props}
onResizeStop={this.onResize.bind(this)}
layout={modifiedLayouts}
>
{widgets}
</Grid> : null}
</div>);
}
}
Logo.defaultProps = {
isDraggable: true,
isResizable: true,
rowHeight: 1,
cols: 12,
}
React.render( <Logo /> , document.getElementById('container'));
感谢 @aepp's elaboration on Github,这个解决方案工作得很好,我已经使用 react-grid-layout@1.3.0
:
测试了这个
import React, {Component} from 'react';
import GridLayout from 'react-grid-layout';
...
//defining the layout inside the "state"
constructor(props) {
super(props);
this.state = {
layout: [
...your_grid_items
],
};
}
...
resizeGridItem = () => {
const layout = this.state.layout.map(item => {...item});
//here you can modify your layout, i.e.
//layout[4].h = 4;
...
this.setState({layout});
}
...
render() {
return (
<div>
<GridLayout
layout={this.state.layout}
...
>
...
</GridLayout>
...
<button onClick={this.resizeGridItem}>Resize</button>
</div>
);
}
有没有办法以编程方式更改项目布局的 w
和 h
?用例是有一个 "collapse" 按钮,它将高度降低到恒定高度,足以离开项目的 header 。为此,我最初的想法是让 layouts
保持在组件的状态,并手动将折叠的 item/s 的高度更改为另一个恒定高度。
然而,似乎库会在初始渲染后忽略对 layout
的更改。是这种情况还是我这边的错误?如果这是正常行为,是否有另一种方法可以通过编程方式更改高度?
这是实现 react-grid-layout
的独立组件。有两个 "widgets" 有一个 "collapse" 的 onClick 处理程序。通过设置状态,它会触发 re-render 并重新计算布局,以便任何折叠的项目都具有降低的高度。控制台日志显示呈现的组件具有正确的新布局,但它没有反映在屏幕上,这让我相信还有另一个对高度的引用。
import React, { Component } from 'react';
import GridLayout, { WidthProvider } from 'react-grid-layout';
const Grid = WidthProvider(GridLayout);
// # WidgetsContainer
// Container WidgetsContainer component.
class WidgetsContainer extends Component {
static defaultProps = {
isDraggable: true,
isResizable: true,
rowHeight: 1,
cols: 12,
}
constructor(props) {
super(props);
this.state = {
layouts: [
{
i: 'item_1',
x: 0,
y: 0,
w: 5,
h: 25,
}, {
i: 'item_2',
x: 5,
y: 0,
w: 7,
h: 30,
},
],
collapsedWidgets: {},
};
}
toggleWidget(id) {
return () => {
const newState = {...this.state.collapsedWidgets};
const collapsed = typeof newState[id] === 'boolean' ? newState[id] : false;
newState[id] = !collapsed;
this.setState({
collapsedWidgets: newState,
});
}
}
onResize(layouts) {
this.setState({
layouts,
});
}
getModifiedLayouts() {
const { layouts, collapsedWidgets } = this.state;
const newLayouts = layouts.map(layout => {
const newLayout = { ...layout };
if (collapsedWidgets[newLayout.i]) {
newLayout.h = 5;
}
return newLayout;
});
return newLayouts;
}
getWidgets() {
const widgets = [{
component: <div style={{ height: '250px', background: 'lightgray' }}>Content</div>,
title: 'Item 1',
id: 'item_1',
}, {
component: <div style={{ height: '310px', background: 'lightgray' }}>Content 2</div>,
title: 'Item 2',
id: 'item_2',
}];
return widgets;
}
generateDOM() {
const widgets = this.getWidgets();
const modifiedLayouts = this.getModifiedLayouts();
return widgets.map((widget, i) => {
return (<div key={i} _grid={modifiedLayouts[i]}>
<div style={{ background: 'gray' }} onClick={::this.toggleWidget(widget.id)}>
{widget.title}
{widget.component}
</div>
</div>);
});
}
render() {
const widgets = this.generateDOM();
console.log(widgets[0].props._grid)
return (<div style={{ marginTop: '15px' }}>
{widgets ? <Grid className="layout"
{...this.props}
onResizeStop={::this.onResize}
>
{widgets}
</Grid> : null}
</div>);
}
}
export default WidgetsContainer;
事实证明,诀窍是不使用 _grid
而是在 Grid
组件上使用 layout
属性。这是一个有效的 jsfiddle:
http://jsfiddle.net/zekedroid/d9o75d24/
和代码:
const Grid = ReactGridLayout.WidthProvider(ReactGridLayout);
class Logo extends React.Component {
constructor(props) {
super(props);
this.state = {
layouts: [
{
i: '0',
x: 0,
y: 0,
w: 5,
h: 25,
}, {
i: '1',
x: 5,
y: 0,
w: 7,
h: 30,
},
],
collapsedWidgets: {},
};
}
toggleWidget(id) {
return () => {
const newState = {...this.state.collapsedWidgets};
const collapsed = typeof newState[id] === 'boolean' ? newState[id] : false;
newState[id] = !collapsed;
this.setState({
collapsedWidgets: newState,
});
}
}
onResize(layouts) {
this.setState({
layouts,
});
}
getModifiedLayouts() {
const { layouts, collapsedWidgets } = this.state;
const newLayouts = layouts.map(layout => {
const newLayout = { ...layout };
if (collapsedWidgets[newLayout.i]) {
newLayout.h = 5;
}
return newLayout;
});
return newLayouts;
}
getWidgets() {
const widgets = [{
component: <div style={{ height: '250px', background: 'lightgray' }}>Content</div>,
title: 'Item 1',
id: '0',
}, {
component: <div style={{ height: '310px', background: 'lightgray' }}>Content 2</div>,
title: 'Item 2',
id: '1',
}];
return widgets;
}
generateDOM() {
const widgets = this.getWidgets();
return widgets.map((widget, i) => {
return (<div key={i} style={{ overflowY: 'auto' }}>
<div style={{ background: 'gray' }} onClick={this.toggleWidget(widget.id).bind(this)}>
{widget.title}
{widget.component}
</div>
</div>);
});
}
render() {
const widgets = this.generateDOM();
const modifiedLayouts = this.getModifiedLayouts();
return (<div style={{ marginTop: '15px' }}>
{widgets ? <Grid className="layout"
{...this.props}
onResizeStop={this.onResize.bind(this)}
layout={modifiedLayouts}
>
{widgets}
</Grid> : null}
</div>);
}
}
Logo.defaultProps = {
isDraggable: true,
isResizable: true,
rowHeight: 1,
cols: 12,
}
React.render( <Logo /> , document.getElementById('container'));
感谢 @aepp's elaboration on Github,这个解决方案工作得很好,我已经使用 react-grid-layout@1.3.0
:
import React, {Component} from 'react';
import GridLayout from 'react-grid-layout';
...
//defining the layout inside the "state"
constructor(props) {
super(props);
this.state = {
layout: [
...your_grid_items
],
};
}
...
resizeGridItem = () => {
const layout = this.state.layout.map(item => {...item});
//here you can modify your layout, i.e.
//layout[4].h = 4;
...
this.setState({layout});
}
...
render() {
return (
<div>
<GridLayout
layout={this.state.layout}
...
>
...
</GridLayout>
...
<button onClick={this.resizeGridItem}>Resize</button>
</div>
);
}