React-Grid-Layout(译文)
缘由: 官方文档纯英文不方便阅读, 且vue有更好的文档地址Vue Grid Layout -️ 适用Vue.js的栅格布局系统
React-Grid-Layout:
git地址: React-Grid-Layout
README.md
React-Grid-Layout是一个网格布局系统就像 Packery 或者Gridster, 用于React.
不像这些系统, 他是响应式和支持断点.断点布局可以提供给用户自己设置或者自动生成.
RGL(react-grid-layout)是仅仅只需要react而不是需求jquery.
GIF from production usage on BitMEX.com
表格目录
- 举例 - Demos
- 特色 - Features
- 安装 - Installation
- 使用 - Usage
- 响应式使用 - Responsive
- 提供网格宽度 - Providing Grid Width
- 网格布局属性 - Grid Layout Props
- 响应式网格布局属性 - Responsive Grid Layout Props
- 网格独立项目属性 - Grid Item Props
- 使用者方法 - User Recipes
- 性能 - Performance
- 贡献 - Contribute
- 备忘录列表 - TODO List
Demos
- 展示 - Showcase
- 基础 - Basic
- 禁止拖拽/调大小(仅仅布局) - No Dragging/Resizing (Layout Only)
- 凌乱布局自动更正 - Messy Layout Autocorrect
- 子节点布局的定义 - Layout Defined on Children
- 静态元素 - Static Elements
- 新增/移除元素 - Adding/Removing Elements
- 保存布局存localstroage - Saving Layout to LocalStorage
- 保存响应式布局存localstroage - Saving a Responsive Layout to LocalStorage
- 最大化/最小化宽高 = Minimum and Maximum Width/Height
- 动态最大最小宽高 - Dynamic Minimum and Maximum Width/Height
- 无需垂直角度压缩(自由运动) - No Vertical Compacting (Free Movement)
- 预防碰撞 - Prevent Collision
- 报错情况 - Error Case
- 工具箱 - Toolbox
- 从外面拉入 - Drag From Outside
- 有界限的布局 - Bounded Layout
- 调整大小事件 - Resizable Handles
- 缩放容器 - Scaled Containers
项目中使用 React-Grid-Layout
- BitMEX
- AWS CloudFront Dashboards
- Grafana
- Metabase
- HubSpot
- ComNetViz
- Stoplight
- Reflect
- ez-Dashing
- Kibana
- Graphext
- Monday
- Quadency
- Hakkiri
- Ubidots
- Statsout
Know of others? Create a PR to let me know!
特色
- 100% React - no jQuery
- 兼容服务端渲染App
- 拖拽组件
- 拉动大小组件
- 静态组件
- 可配置的填充方式: 水平,垂直,或者关闭
- 拖拽和调试大小有边界
- 组件增加或者减少没有重新渲染栅栏
- 布局可以序列化以及恢复Layout can be serialized and restored
- 响应式断点
- 每个响应断点的单独布局
- 栅栏使用c3 transform 来实现拖拽
- 兼容性
<React.StrictMode>
Version | Compatibility |
---|---|
>= 0.17.0 | React 16 & 17 |
>= 0.11.3 | React 0.14 & 15 |
>= 0.10.0 | React 0.14 |
0.8. - 0.9.2 | React 0.13 |
< 0.8 | React 0.12 |
安装
Install the React-Grid-Layout package package using npm:
npm install react-grid-layout
在应用中要包括以下列表(css样式):
/node_modules/react-grid-layout/css/styles.css
/node_modules/react-resizable/css/styles.css
使用
使用ReactGridLayout就像其他的组件.他将遵循以下的例子,一个栅栏包含了三个组件:
- 使用者不能拖拽和调整
a
的大小 - 组件
b
相当于适用一个最小2个栅栏宽度和最大宽度为4个栅栏的元素 - 使用者可以随意的拖拽和调整
c
节点的大小
import GridLayout from 'react-grid-layout';
class MyFirstGrid extends React.Component {
render() {
// layout 是一个对象数组, 查看演示可以了解更多的用法
const layout = [
{i: 'a', x: 0, y: 0, w: 1, h: 2, static: true},
{i: 'b', x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4},
{i: 'c', x: 4, y: 0, w: 1, h: 2}
];
return (
<GridLayout className="layout" layout={layout} cols={12} rowHeight={30} width={1200}>
<div key="a">a</div>
<div key="b">b</div>
<div key="c">c</div>
</GridLayout>
)
}
}
你也可以选择直接在子节点上面直接设置属性
import GridLayout from 'react-grid-layout';
class MyFirstGrid extends React.Component {
render() {
return (
<GridLayout className="layout" cols={12} rowHeight={30} width={1200}>
<div key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}>a</div>
<div key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}>b</div>
<div key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}>c</div>
</GridLayout>
)
}
}
不使用Browserify/Webpack
一个模块使用只要使用一个<script>
包括这里here.他使用umd shim并
不仅仅React
-cli, 所以他还可以使用在requireJs中或者是window.React
响应式使用
做响应式RGL,使用<ResponsiveReactGridLayout>
元素
import { Responsive as ResponsiveGridLayout } from 'react-grid-layout';
class MyResponsiveGrid extends React.Component {
render() {
// {lg: layout1, md: layout2, ...}
const layouts = getLayoutsFromSomewhere();
return (
<ResponsiveGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveGridLayout>
)
}
}
当使用响应式模式, 通过layouts
你应该至少提供一个断点
如果最大提供了,RGL会尝试对其他部分插入
你还需要提供一个width
,当使用<ResponsiveReactGridLayout>
时候,建议你使用HOC高阶组件
WidthProvider
,按照下面的说明
WidthProvider
as per the instructions below.
通过data-grid
属性提供可以支持的属性,所以可以在之后布局插值中使用.
提供栅栏宽度
<ResponsiveReactGridLayout>
和<ReactGridLayout>
需要使用width
来计算拖拽事件的位置.
简单的用例使用HOC高阶组件WidthProvider
可以自动的初始化宽度和窗口调整事件大小.
import { Responsive, WidthProvider } from 'react-grid-layout';
const ResponsiveGridLayout = WidthProvider(Responsive);
class MyResponsiveGrid extends React.Component {
render() {
// {lg: layout1, md: layout2, ...}
var layouts = getLayoutsFromSomewhere();
return (
<ResponsiveGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveGridLayout>
)
}
}
让你可以轻松更换WidthProvider
,为您自己的 Provider HOC,如果您需要更复杂的逻辑的话。
WidthProvider
接受一个 Props,measureBeforeMount
。如果为true,WidthProvider
将在安装(mount) children 之前,测量容器的宽度。如果您想完全消除 应用程序/组件 mount 上的,任何调整大小动画,请使用此选项。
有一个更复杂的布局?WidthProvider
是很简单的,并且只听监听'resize'的窗口事件。如果您需要更多功能和灵活性,请尝试使用SizeMe React HOC,作为 WidthProvider 的替代品。
栅栏布局Props
RGL支持以下属性(最后一句,请参来源)
//
// 基础 props
//
// 这允许在服务器端设置初始宽度.
// 这个是必须的除非使用`<WidthProvider>`或者类似
width: number,
// 如果是true, 这个容器高度会膨胀并且自动适应
autoSize: ?boolean = true,
// 此布局的列数
cols: ?number = 12,
// 一个css选择器作用于tag上让他禁止拖动
// 举个例子: draggableCancel:'.MyNonDraggableAreaClassName'
// 如果你忘了加`.`,他并不会起作用
draggableCancel: ?string = '',
// 一个css选择器作用于tag上让他拖动
// 举个例子: draggableCancel:'.MyNonDraggableAreaClassName'
// 如果你忘了加`.`,他并不会起作用
draggableHandle: ?string = '',
//如果是true,这个布局会垂直压缩
verticalCompact: ?boolean = true,
// Compaction 压缩方向
compactType: ?('vertical' | 'horizontal') = 'vertical';
// layout 是一个对象数组
// 格式化为{x: number, y: number, w: number, h: number}
// 布局中的索引必须与每个项组件上使用的键匹配。
// 如果选择使用自定义关键点,可以在布局中指定该键
// 对象数组就像这样
// {i: string, x: number, y: number, w: number, h: number}
layout: ?array = null, // 如果没有,请使用data-grid属性作用于child
// items之间magin [x, y]单位默认px
margin: ?[number, number] = [10, 10],
// items之间Padding[x, y]单位默认px
containerPadding: ?[number, number] = margin,
// 行高有一个默认高度,但是你可以改变他在断点处
// 就像这样
rowHeight: ?number = 150,
// 配置一个可以拖拽的元素.拖拽的元素是一个"真实"元素
// 从外面拖拽一个元素进来的时候
// 你可以将更好的格式化参数
// i -- id
// w -- width
// h -- height
droppingItem?: { i: string, w: number, h: number }
//
// Flags
//
isDraggable: ?boolean = true,
isResizable: ?boolean = true,
isBounded: ?boolean = false,
// 使用Css3 Translate 替换 position
// 这个可以使性能可以提高6倍
useCSSTransforms: ?boolean = true,
// 如果父节点`ResponsiveReactGridLayout`或者`ReactGridLayout`有`transform: scale(n)`css属性
// 我们需要设置比例系数以避免拖动时渲染
transformScale: ?number = 1,
// 如果true,栅栏不会改变位置
// 拖拽也是一样
preventCollision: ?boolean = false;
//
// 标志
//
isDroppable: ?boolean = false
// 定义呈现调整大小就是正常的栅栏布局
// 's' - South handle (bottom-center)
// 'w' - West handle (left-center)
// 'e' - East handle (right-center)
// 'n' - North handle (top-center)
// 'sw' - Southwest handle (bottom-left)
// 'nw' - Northwest handle (top-left)
// 'se' - Southeast handle (bottom-right)
// 'ne' - Northeast handle (top-right)
resizeHandles: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
// 重新制定大小自定义组件
resizeHandle?: ReactElement<any> | ((resizeHandleAxis: ResizeHandleAxis) => ReactElement<any>)
//
// Callbacks
//
// 回调保存布局
// 得到布局数据在拖拽完成
onLayoutChange: (layout: Layout) => void,
// 所有的回调都有签名
type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void;
// 拖拽移动开始
onDragStart: ItemCallback,
// 拖拽移动
// Calls on each drag movement.
onDrag: ItemCallback,
// Calls when drag is complete.
onDragStop: ItemCallback,
// Calls when resize starts.
onResizeStart: ItemCallback,
// Calls when resize movement happens.
onResize: ItemCallback,
// Calls when resize is complete.
onResizeStop: ItemCallback,
// Calls when an element has been dropped into the grid from outside.
onDrop: (layout: Layout, item: ?LayoutItem, e: Event) => void
// Ref for getting a reference for the grid's wrapping div.
// You can use this instead of a regular ref and the deprecated `ReactDOM.findDOMNode()`` function.
innerRef: ?React.Ref<"div">
响应式栅栏布局 Props
可以使用响应式栅栏布局。它支持上面的所有 Props
除了layout。新属性和更改是:
// {name: pxVal}, 例如: {lg: 1200, md: 996, sm: 768, xs: 480}
// 断点名称是任意的,但必须在 cols和 layouts 对象中,匹配。
breakpoints: ?Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},
// cols 的 #。这是一个断点 -> cols 的 map,例如:{lg: 12, md: 10, ...}
cols: ?Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
// margin 可以指定横向和纵向的margin 就像`[10, 10]` or as a breakpoint -> margin map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
margin: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]}
// 内容padding 可以定制横向与纵向`[10, 10]` or as a breakpoint -> containerPadding map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
containerPadding: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]}
// layouts是一个对象数组
// e.g. {lg: Layout, md: Layout, ...}
layouts: {[key: $Keys<breakpoints>]: Layout}
//
// Callbacks
//
// Calls back with breakpoint and new # cols
onBreakpointChange: (newBreakpoint: string, newCols: number) => void,
// Callback so you can save the layout.
// AllLayouts are keyed by breakpoint.
onLayoutChange: (currentLayout: Layout, allLayouts: {[key: $Keys<breakpoints>]: Layout}) => void,
// 宽度更改时回调,以便根据需要,修改布局。
onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;
栅栏项Props
RGL 的网格项或布局项支持以下属性。初始化网格时,构建一个布局数组(如上面的第一个示例中,所示),或者将此对象附加到,每个子元素的data-grid属性(如第二个示例中,所示)。
请注意,如果提供的网格项不完整(缺少其中一个)x, y, w, or h),将抛出错误,以便更正您的布局。
如果没有为网格项,提供属性,则将生成宽度和高度为1的网格项。
您可以为每个层级,设置最小值和最大值。这是为了调整大小;如果禁用调整大小,它当然没有效果。如果您的最小值和最大值,重叠不正确,或者您的初始尺寸超出范围,则会引发错误。
<GridItem>
直接定义的任何属性,优先于全局设置选项。例如,如果布局具有isDraggable: false属性,但网格项 Props 有 isDraggable: true,该项将是可拖动的。
{
// 一个 字符串,对应组件的 key
i: string,
// 在 grid 单元中的所有, 不是 像素(px)
x: number,
y: number,
w: number,
h: number,
minW: ?number = 0,
maxW: ?number = Infinity,
minH: ?number = 0,
maxH: ?number = Infinity,
// 如果为 true, 等于`isDraggable: false, isResizable: false`.
static: ?boolean = false,
// 如果为 false, 则不能拖放 draggable. 被 `static` 覆盖.
isDraggable: ?boolean = true,
// 如果为 false, 则不能调整大小 resizable. 被 `static` 覆盖.
isResizable: ?boolean = true,
resizeHandles?: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
// 如果为true item只会在网络中移动
isBounded: ?boolean = false
}
性能
<ReactGridLayout>
has an optimized shouldComponentUpdate
implementation, 但它依赖于用户 children
数组:
// lib/ReactGridLayout.jsx
// ...
shouldComponentUpdate(nextProps: Props, nextState: State) {
return (
// 笔记: 这个几乎是不平等的,因此这是获取性能唯一途径
// 从SCU 如果用户有意将子对象记忆起来。如果他们这样做了,他们可以
// 正确处理更改,性能将提高。
this.props.children !== nextProps.children ||
!fastRGLPropsEqual(this.props, nextProps, isEqual) ||
!isEqual(this.state.activeDrag, nextState.activeDrag)
);
}
// ...
如果你有记忆你的子节点,你可以利用这点,会更快的render
比如:
function MyGrid(props) {
const children = React.useMemo(() => {
return new Array(props.count).fill(undefined).map((val, idx) => {
return <div key={idx} data-grid={{x: idx, y: 1, w: 1, h: 1}} />;
});
}, [props.count]);
return <ReactGridLayout cols={12}>{children}</ReactGridLayout>;
}
因为children
属性在两次重播之间不会改变,更新<MyGrid>
不会导致新的渲染,提高性能
Because the children
prop doesn't change between rerenders, updates to <MyGrid>
won't result in new renders, improving performance.
贡献
如果您有功能请求,请将其添加为问题或提出请求。
如果你有bug请求,请修复这个bug在CodeSandbox 去帮助我们更简单的完善他.
待办事项列表
- Basic grid layout
- Fluid grid layout
- Grid packing
- Draggable grid items
- Live grid packing while dragging
- Resizable grid items
- Layouts per responsive breakpoint
- Define grid attributes on children themselves (
data-grid
key) - Static elements
- Persistent id per item for predictable localstorage restores, even when # items changes
- Min/max w/h per item
- Resizable handles on other corners
- Configurable w/h per breakpoint