mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat:Grid 2D 布局容器 (#1339)
* grid 2d 布局初步 * 补充文档 * 文档补充 * 补充文档;支持设置高宽;支持设置格子内布局居中
This commit is contained in:
parent
038c7f57f9
commit
6235d91042
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Grid 网格
|
||||
title: Grid 水平布局
|
||||
description:
|
||||
type: 0
|
||||
group: null
|
||||
|
276
docs/zh-CN/components/grid-2d.md
Normal file
276
docs/zh-CN/components/grid-2d.md
Normal file
@ -0,0 +1,276 @@
|
||||
---
|
||||
title: Grid 2D 布局
|
||||
description:
|
||||
type: 0
|
||||
group: ⚙ 组件
|
||||
menuName: Grid 2D 组件
|
||||
icon:
|
||||
order: 47
|
||||
---
|
||||
|
||||
Grid 2D 是一种二维布局方式,它可以更直观设置组件位置。
|
||||
|
||||
> Grid 2D 布局不支持 IE11
|
||||
|
||||
## 基本用法
|
||||
|
||||
```schema: scoped="body"
|
||||
{
|
||||
"type": "grid-2d",
|
||||
"grids": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 6,
|
||||
"gridClassName": "bg-green-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-1] x:1 y:1 h:1 w:6"
|
||||
},
|
||||
{
|
||||
"x": 7,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 6,
|
||||
"gridClassName": "bg-blue-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-2] x:7 y:1 h:1 w:6"
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"h": 2,
|
||||
"w": 4,
|
||||
"gridClassName": "bg-red-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-3] x:1 y:2 h:2 w:4"
|
||||
},
|
||||
{
|
||||
"x": 5,
|
||||
"y": 2,
|
||||
"h": 1,
|
||||
"w": 8,
|
||||
"gridClassName": "bg-purple-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-4] x:5 y:2 h:1 w:8"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 布局基础
|
||||
|
||||
`grids` 中可以是任意组件,这里为了简化使用 tpl 组件,通过 x/y/h/w 这四个属性来控制格子的位置和大小。
|
||||
|
||||
首先看下图示例,它就是前面基本用法的示例加上标注:
|
||||
|
||||
![grid](../../../examples/static/grid-2d.png)
|
||||
|
||||
默认水平方向会平分为 12 列,可以通过 `cols` 来调整,比如只分为 3 栏。
|
||||
|
||||
先看 `[grid-1]`,它的 `x/y/h/w` 值分别是 `1,1,1,6`:
|
||||
|
||||
- `x,y` 决定这个格子的位置,`1,1` 就是最左上角的位置,如图所示
|
||||
- `w` 代表宽度占几格,因为水平方向一共 12 列,所以 6 就意味着占水平空间一半
|
||||
- `h` 代表高度占几格,默认每行高度可以使用 `rowHeight` 来控制,也可以设置 `height` 来单独控制这一行的高度
|
||||
|
||||
其它格子也可以参照这张图推理出来,比如 `[grid-2]` 起始 x 位置是 `7`,宽度是 6,因此它和 `[grid-]` 平分了第一行。
|
||||
|
||||
## 独立设置高宽
|
||||
|
||||
在上面的例子中格子的宽度是根据页面宽度平分,高度是固定的,但我们也可以单独改变某一行或某一列的高宽,方法是格子上的 `width` 和 `height` 值。
|
||||
|
||||
看下面这个例子
|
||||
|
||||
```schema: scoped="body"
|
||||
{
|
||||
"type": "grid-2d",
|
||||
"cols": 3,
|
||||
"grids": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"width": 100,
|
||||
"gridClassName": "bg-green-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-1] x:1 y:1 h:1 w:1"
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"height": 100,
|
||||
"gridClassName": "bg-blue-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-2] x:2 y:1 h:1 w:1"
|
||||
},
|
||||
{
|
||||
"x": 3,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"width": 100,
|
||||
"gridClassName": "bg-red-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-3] x:3 y:1 h:1 w:1"
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"gridClassName": "bg-purple-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-4] x:2 y:2 h:1 w:1"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
在这个例子中,首先通过 `cols` 设置了列数为 `3`,然后将 `[grid-1]` 和 `[grid-3]` 的 width 设置为 `100`,使得这两列的宽度都是 100,而页面剩下的宽度就全都留给了 `[grid-2]`。
|
||||
|
||||
而在 `[grid-2]` 中通过 `height` 设置了高度,使得这一行高度是 `100px`,而不是默认的 `50px`。
|
||||
|
||||
请注意:`width` 将影响一整列,`height` 将影响一整行。
|
||||
|
||||
## 自适应内容高度
|
||||
|
||||
如果格子内容高度不确定,想更具内容自动撑开,可以设置 `width` 为 `auto`。
|
||||
|
||||
```schema: scoped="body"
|
||||
{
|
||||
"type": "grid-2d",
|
||||
"cols": 3,
|
||||
"grids": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"height": "auto",
|
||||
"gridClassName": "bg-blue-300",
|
||||
"type": "tpl",
|
||||
"tpl": "1</br>2</br>3</br>4</br>5</br>6</br>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 格子间距 gap / rowGap
|
||||
|
||||
通过 grip 上的 gap 属性来控制间距,默认包含水平和垂直间距
|
||||
|
||||
```schema: scoped="body"
|
||||
{
|
||||
"type": "grid-2d",
|
||||
"gap": 10,
|
||||
"gapRow": 5,
|
||||
"grids": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 6,
|
||||
"gridClassName": "bg-green-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-1] x:1 y:1 h:1 w:6"
|
||||
},
|
||||
{
|
||||
"x": 7,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 6,
|
||||
"gridClassName": "bg-blue-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-2] x:7 y:1 h:1 w:6"
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"h": 2,
|
||||
"w": 4,
|
||||
"gridClassName": "bg-red-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-3] x:1 y:2 h:2 w:4"
|
||||
},
|
||||
{
|
||||
"x": 5,
|
||||
"y": 2,
|
||||
"h": 1,
|
||||
"w": 8,
|
||||
"gridClassName": "bg-purple-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-4] x:5 y:2 h:1 w:8"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 内容区域小于格子的摆放
|
||||
|
||||
默认情况下,格子的高宽会撑满对应区域的高宽,但有时候内容高宽比这个格子小,比如一张图片,如何将它在各种中居中显示?
|
||||
|
||||
看下面的例子
|
||||
|
||||
```schema: scoped="body"
|
||||
{
|
||||
"type": "grid-2d",
|
||||
"cols": 3,
|
||||
"grids": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"gridClassName": "bg-green-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-1] x:1 y:1 h:1 w:1"
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"align": "center",
|
||||
"vAlign": "middle",
|
||||
"gridClassName": "bg-blue-300",
|
||||
"type": "tpl",
|
||||
"tpl": "hello"
|
||||
},
|
||||
{
|
||||
"x": 3,
|
||||
"y": 1,
|
||||
"h": 1,
|
||||
"w": 1,
|
||||
"gridClassName": "bg-red-300",
|
||||
"type": "tpl",
|
||||
"tpl": "[grid-3] x:3 y:1 h:1 w:1"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
在中间的格子中,我们设置了 `"align": "center"` 和 `"vAlign": "middle"`,就使得文字水平和垂直居中显示了。
|
||||
|
||||
## 属性表
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| --------------- | --------------------------------- | ----------- | ------------------------------- |
|
||||
| type | `string` | `"grid-2d"` | 指定为 Grid 2D 渲染器 |
|
||||
| gridClassName | `string` | | 外层 Dom 的类名 |
|
||||
| gap | `int`/`string` | 0 | 格子间距,包括水平和垂直 |
|
||||
| cols | `int` | 12 | 格子水平划分为几个区域 |
|
||||
| rowGap | `int`/`string` | | 格子垂直间距 |
|
||||
| grids | `Array` | | 格子集合 |
|
||||
| grids[x] | [SchemaNode](../types/schemanode) | | 格子可以是其他渲染器 |
|
||||
| grids[x].x | `int` | | 格子起始位置的横坐标 |
|
||||
| grids[x].y | `int` | | 格子起始位置的纵坐标 |
|
||||
| grids[x].w | `int` | | 格子横跨几个宽度 |
|
||||
| grids[x].h | `int` | | 格子横跨几个高度 |
|
||||
| grids[x].width | `int`/`string`/`auto` | | 格子所在列的宽度 |
|
||||
| grids[x].height | `int`/`string`/`auto` | | 格子所在行的高度,可以设置 auto |
|
||||
| grids[x].align | 'left'/'center'/'right'/'auto' | 'auto' | 格子内容水平 |
|
||||
| grids[x].vAlign | 'top'/'bottom'/'middle'/'auto' | 'auto' | 格子所在行的高度,可以设置 auto |
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
title: Grid 网格布局
|
||||
title: Grid 水平布局
|
||||
description:
|
||||
type: 0
|
||||
group: ⚙ 组件
|
||||
menuName: Grid 格线组件
|
||||
menuName: Grid 组件
|
||||
icon:
|
||||
order: 46
|
||||
---
|
||||
|
@ -372,7 +372,7 @@ export default [
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'Grid 网格',
|
||||
label: 'Grid 水平布局',
|
||||
path: '/zh-CN/docs/components/form/grid',
|
||||
getComponent: () =>
|
||||
// @ts-ignore
|
||||
@ -869,7 +869,7 @@ export default [
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'Grid 网格布局',
|
||||
label: 'Grid 水平布局',
|
||||
path: '/zh-CN/docs/components/grid',
|
||||
getComponent: () =>
|
||||
// @ts-ignore
|
||||
@ -877,6 +877,15 @@ export default [
|
||||
makeMarkdownRenderer
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'Grid 2D 布局',
|
||||
path: '/zh-CN/docs/components/grid-2d',
|
||||
getComponent: () =>
|
||||
// @ts-ignore
|
||||
import('../../docs/zh-CN/components/grid-2d.md').then(
|
||||
makeMarkdownRenderer
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'HBox 布局',
|
||||
path: '/zh-CN/docs/components/hbox',
|
||||
|
BIN
examples/static/grid-2d.png
Normal file
BIN
examples/static/grid-2d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
@ -20,6 +20,7 @@ import {DividerSchema} from './renderers/Divider';
|
||||
import {DropdownButtonSchema} from './renderers/DropDownButton';
|
||||
import {EachSchema} from './renderers/Each';
|
||||
import {GridSchema} from './renderers/Grid';
|
||||
import {Grid2DSchema} from './renderers/Grid2D';
|
||||
import {HBoxSchema} from './renderers/HBox';
|
||||
import {IconSchema} from './renderers/Icon';
|
||||
import {IFrameSchema} from './renderers/IFrame';
|
||||
@ -85,6 +86,7 @@ export type SchemaType =
|
||||
| 'drawer'
|
||||
| 'each'
|
||||
| 'grid'
|
||||
| 'grid-2d'
|
||||
| 'hbox'
|
||||
| 'icon'
|
||||
| 'iframe'
|
||||
@ -151,6 +153,7 @@ export type SchemaObject =
|
||||
| DropdownButtonSchema
|
||||
| EachSchema
|
||||
| GridSchema
|
||||
| Grid2DSchema
|
||||
| HBoxSchema
|
||||
| IconSchema
|
||||
| IFrameSchema
|
||||
|
@ -115,6 +115,7 @@ import './renderers/Form/TabsTransfer';
|
||||
import './renderers/Form/Group';
|
||||
import './renderers/Form/InputGroup';
|
||||
import './renderers/Grid';
|
||||
import './renderers/Grid2D';
|
||||
import './renderers/HBox';
|
||||
import './renderers/VBox';
|
||||
import './renderers/Image';
|
||||
|
222
src/renderers/Grid2D.tsx
Normal file
222
src/renderers/Grid2D.tsx
Normal file
@ -0,0 +1,222 @@
|
||||
import React from 'react';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {Api, SchemaNode, Schema, Action} from '../types';
|
||||
import {isVisible} from '../utils/helper';
|
||||
import {BaseSchema, SchemaObject} from '../Schema';
|
||||
|
||||
export type GridObject = {
|
||||
/**
|
||||
* 起始横坐标位置,以 1 为起点
|
||||
*/
|
||||
x: number;
|
||||
|
||||
/**
|
||||
* 起始纵坐标位置,以 1 为起点
|
||||
*/
|
||||
y: number;
|
||||
|
||||
/**
|
||||
* 宽度,跨几列
|
||||
*/
|
||||
w: number;
|
||||
|
||||
/**
|
||||
* 高度,跨几行
|
||||
*/
|
||||
h: number;
|
||||
|
||||
/**
|
||||
* 宽度,会影响起始位置对应那一列的宽度
|
||||
*/
|
||||
width?: number | string;
|
||||
|
||||
/**
|
||||
* 高度,会影响起始位置那一行的高度,设置为 auto 就会自适应
|
||||
*/
|
||||
height?: number | string;
|
||||
|
||||
/**
|
||||
* 水平展示方式,用于内容宽度比 grid 小的情况,默认是 auto 自动撑满
|
||||
*/
|
||||
align?: 'left' | 'right' | 'center' | 'auto';
|
||||
|
||||
/**
|
||||
* 垂直展示方式,用于内容高度比 grid 小的情况,默认是 auto 自动撑满
|
||||
*/
|
||||
vAlign?: 'top' | 'bottom' | 'middle' | 'auto';
|
||||
|
||||
/**
|
||||
* 每个格子最外层容器的 className
|
||||
*/
|
||||
gridClassName?: string;
|
||||
};
|
||||
|
||||
export type Grid = GridObject & SchemaObject;
|
||||
|
||||
/**
|
||||
* 二维布局渲染器。
|
||||
* 文档:https://baidu.gitee.io/amis/docs/components/grid-2d
|
||||
*/
|
||||
export interface Grid2DSchema extends BaseSchema {
|
||||
/**
|
||||
* 指定为each展示类型
|
||||
*/
|
||||
type: 'grid-2d';
|
||||
|
||||
/**
|
||||
* 列数量,默认是 12
|
||||
*/
|
||||
cols?: number;
|
||||
|
||||
/**
|
||||
* grid 2d 容器宽度,默认是 auto
|
||||
*/
|
||||
width?: number | string | 'auto';
|
||||
|
||||
/**
|
||||
* 格子间距,默认 0,包含行和列
|
||||
*/
|
||||
gap?: number | string;
|
||||
|
||||
/**
|
||||
* 格子行级别的间距,如果不设置就和 gap 一样
|
||||
*/
|
||||
gapRow?: number | string;
|
||||
|
||||
/**
|
||||
* 单位行高度,默认 50 px
|
||||
*/
|
||||
rowHeight?: number | string;
|
||||
|
||||
/**
|
||||
* 每个格子的配置
|
||||
*/
|
||||
grids: Array<Grid>;
|
||||
}
|
||||
|
||||
export interface Grid2DProps extends RendererProps, Grid2DSchema {
|
||||
itemRender?: (
|
||||
item: any,
|
||||
key: number,
|
||||
length: number,
|
||||
props: any
|
||||
) => JSX.Element;
|
||||
}
|
||||
|
||||
// Grid 布局默认的这个命名方式和其它 CSS 差异太大,所以我们使用更类似其它 CSS 的命名
|
||||
const justifySelfMap = {
|
||||
left: 'start',
|
||||
right: 'end',
|
||||
center: 'center',
|
||||
auto: 'stretch'
|
||||
};
|
||||
|
||||
const alignSelfMap = {
|
||||
top: 'start',
|
||||
bottom: 'end',
|
||||
middle: 'center',
|
||||
auto: 'stretch'
|
||||
};
|
||||
|
||||
export default class Grid2D extends React.Component<Grid2DProps, object> {
|
||||
static propsList: Array<string> = ['grids'];
|
||||
|
||||
static defaultProps: Partial<Grid2DProps> = {
|
||||
cols: 12,
|
||||
width: 'auto',
|
||||
gap: 0,
|
||||
rowHeight: '3.125rem'
|
||||
};
|
||||
|
||||
constructor(props: Grid2DProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
renderChild(region: string, node: Schema) {
|
||||
const {render} = this.props;
|
||||
|
||||
return render(region, node);
|
||||
}
|
||||
|
||||
renderGrid(grid: Grid, key: number, length: number) {
|
||||
const {itemRender, data} = this.props;
|
||||
|
||||
if (!isVisible(grid, data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let style: any = {
|
||||
gridColumnStart: grid.x,
|
||||
gridColumnEnd: grid.x + grid.w,
|
||||
gridRowStart: grid.y,
|
||||
gridRowEnd: grid.y + grid.h,
|
||||
justifySelf: grid.align ? justifySelfMap[grid.align] : 'stretch',
|
||||
alignSelf: grid.vAlign ? alignSelfMap[grid.vAlign] : 'stretch'
|
||||
};
|
||||
|
||||
return (
|
||||
<div key={key} style={style} className={grid.gridClassName}>
|
||||
{itemRender
|
||||
? itemRender(grid, key, length, this.props)
|
||||
: this.renderChild(`grid2d/${key}`, grid)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderGrids() {
|
||||
const {grids} = this.props;
|
||||
|
||||
return grids.map((grid, key) => this.renderGrid(grid, key, grids.length));
|
||||
}
|
||||
|
||||
render() {
|
||||
const {grids, cols, gap, gapRow, width, rowHeight} = this.props;
|
||||
|
||||
const templateColumns = new Array(cols);
|
||||
templateColumns.fill('1fr');
|
||||
|
||||
let maxRow = 0;
|
||||
|
||||
// 计算最大有多少行
|
||||
grids.forEach((grid, index) => {
|
||||
let row = grid.y + grid.h - 1;
|
||||
if (row > maxRow) {
|
||||
maxRow = row;
|
||||
}
|
||||
});
|
||||
|
||||
const templateRows = new Array(maxRow);
|
||||
templateRows.fill(rowHeight);
|
||||
|
||||
// 根据 grid 中的设置自动更新行列高度
|
||||
grids.forEach(grid => {
|
||||
if (grid.width) {
|
||||
templateColumns[grid.x - 1] = Number.isInteger(grid.width)
|
||||
? grid.width + 'px'
|
||||
: grid.width;
|
||||
}
|
||||
if (grid.height) {
|
||||
templateRows[grid.y - 1] = Number.isInteger(grid.height)
|
||||
? grid.height + 'px'
|
||||
: grid.height;
|
||||
}
|
||||
});
|
||||
|
||||
const style = {
|
||||
display: 'grid',
|
||||
columnGap: gap,
|
||||
rowGap: typeof gapRow === 'undefined' ? gap : gapRow,
|
||||
width,
|
||||
gridTemplateColumns: templateColumns.join(' '),
|
||||
gridTemplateRows: templateRows.join(' ')
|
||||
};
|
||||
|
||||
return <div style={style}>{this.renderGrids()}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)grid-2d$/,
|
||||
name: 'grid-2d'
|
||||
})
|
||||
export class Grid2DRenderer extends Grid2D {}
|
Loading…
Reference in New Issue
Block a user