layout 参考文档
https://github.com/react-grid-layout/react-grid-layout#demos
- 最外层的元素要设置 overflow: ‘hidden’,否则拖拽会有滚动条 ```tsx import { useMemo } from ‘react’; import { WidthProvider, Responsive } from ‘react-grid-layout’; import { array, func, number, object, string } from ‘prop-types’; import { merge } from ‘lodash-es’; import cls from ‘classnames’; import ‘react-grid-layout/css/styles.css’; import ‘react-resizable/css/styles.css’;
const layout = [ { i: ‘a’, x: 0, y: 0, w: 4, h: 1, minW: 3 }, { i: ‘b’, x: 4, y: 0, w: 4, h: 1, minW: 3, maxW: 4 }, { i: ‘c’, x: 8, y: 0, w: 4, h: 1, minW: 3 }, { i: ‘d’, x: 0, y: 1, w: 4, h: 1, minW: 3 }, { i: ‘e’, x: 4, y: 1, w: 4, h: 1, minW: 3 }, ];
// 大屏幕 12列,小屏幕 6列,手机端一列 const defaultCols = { lg: 12, md: 12, sm: 6, xs: 3, xxs: 1 };
ReactGridLayout.propTypes = { dataSource: array.isRequired, onLayoutChange: func.isRequired, gutter: array, rowHeight: number, cols: object, className: string, }; ReactGridLayout.defaultProps = { gutter: [16, 24], rowHeight: 80, };
function ReactGridLayout(props) { const { rowHeight } = props;
const GridLayout = useMemo(() => WidthProvider(Responsive), []);
return (
export default ReactGridLayout;
- WidthProvider 只监听窗口'resize'事件
- Response 响应模式下,该属性提供至少一个断点 layouts
- Size响应式 [https://github.com/ctrlplusb/react-sizeme](https://github.com/ctrlplusb/react-sizeme)
- draggableHandle=".head-title" 只能拖拽的元素
- isBounded 只能在 grid里面拖拽
<a name="pk7ip"></a>
### rowHeight
实际像素高度 = (rowHeight * h) + marginH * (h - 1)
- 例如,rowHeight={80}, margin={[24, 24]},实际元素的高度 = (80 * 3) + 24 * (3-1) = 288
- 宽度会根据多少列,自动计算
- { i: 'a', x: 0, y: 0, w: 4, h: 1, minW: 3 },
![image.png](https://cdn.nlark.com/yuque/0/2023/png/112859/1690511562812-1f86a95a-5be3-4130-ad47-5a6aabb03689.png#averageHue=%23c6d8f3&clientId=u30ddcccd-3015-4&from=paste&height=76&id=u31e7c8ae&originHeight=168&originWidth=1408&originalType=binary&ratio=2.200000047683716&rotation=0&showTitle=false&size=99589&status=done&style=none&taskId=u098cda6d-a415-446f-a971-0060ddff073&title=&width=639.9999861283738)
<a name="iNQSI"></a>
## layout布局
```jsx
const layout = [
{
i: 'a', // 组件key值,必须是唯一的
x: 0, // 组件在x轴坐标,占多少列
y: 0, // 组件在y轴坐标,
w: 4, // width 宽度,占据多少列宽
h: 3, // height 高度,3的意思是 rowHeight 的倍数; 3 * rowHeight
// minW: 2, // 最小宽度
},
{ i: 'b', x: 4, y: 0, w: 4, h: 3 },
{ i: 'c', x: 8, y: 0, w: 4, h: 3 },
{ i: 'd', x: 0, y: 1, w: 4, h: 3 },
{ i: 'e', x: 4, y: 1, w: 4, h: 3 },
];
- i 与组件 key相对应的 key
- static,固定布局,不可以拖拽
- static: true,以下都为 isDraggable: false, isResizable: false
- resizeHandles 拖拽手柄,默认只显示右下角手柄
gridItem 属性配置
https://github.com/react-grid-layout/react-grid-layout#grid-item-props
grid配置项要完整,例如:缺少其中一项x, y, w, or h,则会抛出错误
可以设置每个 grid维度的最小值 minH, minW 和最大值 maxH, maxW
{
// A string corresponding to the component key
i: string,
// These are all in grid units, not pixels
x: number,
y: number,
w: number,
h: number,
minW: ?number = 0,
maxW: ?number = Infinity,
minH: ?number = 0,
maxH: ?number = Infinity,
// If true, equal to `isDraggable: false, isResizable: false`.
static: ?boolean = false,
// If false, will not be draggable. Overrides `static`.
isDraggable: ?boolean = true,
// If false, will not be resizable. Overrides `static`.
isResizable: ?boolean = true,
// By default, a handle is only shown on the bottom-right (southeast) corner.
// Note that resizing from the top or left is generally not intuitive.
resizeHandles?: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
// If true and draggable, item will be moved only within grid.
isBounded: ?boolean = false
}
data-grid
import { useMemo } from 'react';
import { WidthProvider, Responsive } from 'react-grid-layout';
import { array, func, number, object, string } from 'prop-types';
import { merge } from 'lodash-es';
import cls from 'classnames';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
const dataSource = [
{ label: "Table", value: 1 },
{ label: "List", value: 2 },
{ label: "Card", value: 3 },
{ label: "Chart", value: 4 },
{ label: "Topo", value: 5 }
];
const defaultCols = { lg: 12, md: 12, sm: 6, xs: 3, xxs: 1 };
ReactGridLayout.propTypes = {
dataSource: array.isRequired,
onLayoutChange: func.isRequired,
gutter: array,
rowHeight: number,
cols: object,
className: string,
};
ReactGridLayout.defaultProps = {
gutter: [16, 24],
rowHeight: 80,
};
function ReactGridLayout(props) {
const {
rowHeight
} = props;
const GridLayout = useMemo(() => WidthProvider(Responsive), []);
// 性能更好的子节点渲染
const children = useMemo(() => {
return dataSource.map((item, index) => {
const grid = {
x: (index % 3) * 4, // 组件在x轴坐标
y: Math.floor(index / 3),
w: 4,
h: 3,
minW: 2,
// maxW: 12,
isBounded: true
};
return (
<div
key={index}
data-grid={grid}
>
{item.label}
</div>
);
});
}, [dataSource]);
const onLayoutChange(layout) {
setState(layout);
// localStorage.setItem(KEY, JSON.stringify(layout));
}
return (
<GridLayout
className={cls('__react-grid-layout__', className)}
// 响应式布局断点
// layouts={{ lg: layout, md: layout, sm: layout }}
// layout={layout}
cols={merge(defaultCols, cols)}
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
rowHeight={rowHeight}
margin={[24, 24]}
containerPadding={[0, 0]}
resizeHandles={['ne', 'se']}
onLayoutChange={onLayoutChange}
>
{children}
</GridLayout>
)
}
export default ReactGridLayout;
自定义 GridItem
需要将 style、className、onMouseDown、onMouseUp转发 onTouchEnd到同一个 DOM 节点
const CustomGridItem = React.forwardRef((props, ref) => {
const {
style,
className,
onMouseDown,
onMouseUp,
onTouchEnd,
children,
...rest
} = props;
return (
<div
style={{...style}}
className={className}
ref={ref}
onMouseDown={onMouseDown}
onMouseUp={onMouseUp}
onTouchEnd={onTouchEnd}
>
{/* Make sure to include children to add resizable handle */}
{children}
</div>
);
})
draggableHandle 自定义可拖动手柄也需要透传以上属性