译:react-grid-layout

4,825 阅读5分钟

用于react,具备响应式断点的可拖拽可缩放的组件

安装

使用npm安装包

npm install react-grid-layout

在css文件中引入插件样式

@import '~react-grid-layout/css/styles.css'; 
@import '~react-resizable/css/styles.css';

使用

简单案例:

下面的例子是由三个div(a,b,c)构成的栅格布局

  • item a 不能被拖拽和缩放
  • item b 被限制拖拽,最小宽度为2个栅格块,最大宽度为4个栅格块
  • item c 可以被自由的拖拽和缩放
import GridLayout from 'react-grid-layout';

class MyFirstGrid extends React.Component {
  render() {
    // layout is an array of objects, see the demo for more complete usage
    var 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>
    )
  }
}

也可以将layout这个布局属性直接设置在每个元素身上

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>
    )
  }
}

响应式的使用

为了实现响应式的栅格布局, 使用 <ResponsiveReactGridLayout> 组件

import { Responsive as ResponsiveGridLayout } from 'react-grid-layout';

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>
    )
  }
}

在响应式模式下,需要在layouts属性里至少设置一个断点

当使用layouts,提供越多的断点越好,特别是最大的断点。如果提供了最大的断点,栅格布局将尝试有显示有这个布局。

在使用<ResponsiveReactGridLayout>组件时,需要提供width,在下面的知道中建议使用高阶组件WidthProvider来提供width

暂时不支持通过data-grid实行为某单独的item提供响应式

提供栅格宽度

<ResponsiveReactGridLayout> 和<ReactGridLayout>都是通过width在拖拽事件中计算位置。可以使用高阶组件WidthProvider在初始化和页面尺寸发生变化的时候自动决定width

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替换成你自定义的高阶组件。

WidthProvider接收一个参数:measureBeforeMount。如果为true,WidthProvider将在加载子组件之前测量容器的宽度, 如果你想完全消除应用程序/组件挂载上的任何调整动画,使用这个选项。

如果布局足够复杂呢?WidthProvider很简单,只监听了window的resize事件。如果你需要更大的灵活性,可尝试SizeMe高阶组件作为替代方案

栅格布局参数

自添加ps:<ResponsiveReactGridLayout>组件的属性

//基础属性
//允许在服务器端设置初始宽度
// 要求使用<WidthProvider>或者更简单的高阶组件
width: number
//如果为true,容器的高度将适应内容进行放大缩小
autoSize: ?boolean = true,

// 这个布局的列数
cols: ?number = 12,

一个css选择器标签,将不会被拖拽,如果忘记了“.”, 将不起作用,例如:
// For example: draggableCancel:'.MyNonDraggableAreaClassName'
draggableCancel: ?string = '',

一个css选择器作为标签,可以被拖拽。,如果忘记了“.”, 将不起作用,例如:
// For example: draggableHandle:'.MyDragHandleClassName'
draggableHandle: ?string = '',

// If true, the layout will compact vertically
// 如果设置为true,布局将是垂直紧密排列
verticalCompact: ?boolean = true,

// 紧密排列的方向
compactType: ?('vertical' | 'horizontal') = 'vertical';

layout的格式是一个数组,每一项为一个对象,如下:
// {x: number, y: number, w: number, h: number}
//layout里的索引值i(index)需要和每个具体拖拽组件的key属性保持一致。
//如果使用了自定义的key值,可以把这个值定义到layout当中
// array objects like so:
// {i: string, x: number, y: number, w: number, h: number}
layout: ?array = null, // If not provided, use data-grid props on children

//具体拖拽项之间的margin,单位为px
margin: ?[number, number] = [10, 10],

//容器的padding,单位为px
containerPadding: ?[number, number] = margin,

每行有固定高度,可以基于断点来改变
rowHeight: ?number = 150,

//
// Flags 标记
//
isDraggable: ?boolean = true,
isResizable: ?boolean = true,
//使用css3的translate() 代替 position top/left,带来快6倍的性能
useCSSTransforms: ?boolean = true,

//如果设置true,在拖拽过程当中,具体拖拽组件不会改变位置
preventCollision: ?boolean = false;

//
// Callbacks 回调
//


//用来保存布局的回调,每次拖拽或者页面大小改变结束 返回当前的布局
onLayoutChange: (layout: Layout) => void,

//
//下面所有的回调都有这些参数(layout, oldItem, newItem, placeholder, e, element)
//开始和结束事件的placeholder为undefined
type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
                     placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void;

// Calls when drag starts.
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

响应式布局参数

支持以上所有参数,除了layout。新的属性和变化如下:

// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
// Breakpoint names are arbitrary but must match in the cols and layouts objects.
//断点的名称可以是任意的,但是需要和layouts和cols对象保持一致
breakpoints: ?Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},

// # of cols. This is a breakpoint -> cols map, e.g. {lg: 12, md: 10, ...}
cols: ?Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},

// layouts is an object mapping breakpoints to 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,

// Callback when the width changes, so you can modify the layout as needed.
onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;