Tabs 支持 source 关联数据循环 (#1496)

* Tabs 支持 source 关联数据循环

* visibleOn 的判断传参错误
This commit is contained in:
liaoxuezhi 2021-02-01 19:41:13 +08:00 committed by GitHub
parent 26ef7d0819
commit a000fa7c94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 183 additions and 30 deletions

View File

@ -27,6 +27,43 @@ order: 68
}
```
默认想要显示多少选项卡配置多少个 `tabs` 成员即可。但是有时候你可能会想根据某个数据来动态生成。这个时候需要额外配置 `source` 属性如。
```schema
{
"type": "page",
"data": {
"arr": [
{
"a": "收入",
"b": 199
},
{
"a": "支出",
"b": 299
}
]
},
"body": [
{
"type": "tabs",
"source": "${arr}",
"tabs": [
{
"title": "${a}",
"body": {
"type": "tpl",
"tpl": "金额:${b|number}元"
}
}
]
}
]
}
```
## 展示模式
### 线型
@ -315,6 +352,7 @@ order: 68
| mode | `string` | | 展示模式,取值可以是 `line`、`card`、`radio`、`vertical` |
| tabsClassName | `string` | | Tabs Dom 的类名 |
| tabs | `Array` | | tabs 内容 |
| source | `string` | | tabs 关联数据,关联后可以重复生成选项卡 |
| toolbar | [SchemaNode](../types/schemanode) | | tabs 中的工具栏 |
| toolbarClassName | `string` | | tabs 中工具栏的类名 |
| tabs[x].title | `string` | | Tab 标题 |

View File

@ -75,6 +75,7 @@ import IFrameSchema from './IFrame';
import NormalTabSchema from './Tabs/Normal';
import FormTabSchema from './Tabs/Form';
import DynamicTabSchema from './Tabs/Dynamic';
import Tab1Schema from './Tabs/Tab1';
import Tab2Schema from './Tabs/Tab2';
import Tab3Schema from './Tabs/Tab3';
@ -400,6 +401,12 @@ export const examples = [
path: '/examples/tabs/form',
component: makeSchemaRenderer(FormTabSchema)
},
{
label: '动态选项卡',
path: '/examples/tabs/dynamic',
component: makeSchemaRenderer(DynamicTabSchema)
},
{
label: '选项卡页面1',
path: '/examples/tabs/tab1',

View File

@ -0,0 +1,36 @@
export default {
type: 'page',
title: '动态选项卡',
subTitle: '根据变量动态生成',
data: {
arr: [
{
label: '收入',
value: 123
},
{
label: '支出',
value: 233
}
]
},
body: [
{
type: 'tabs',
source: '${arr}',
mode: 'card',
tabs: [
{
title: '${label}-A',
body: '选项卡内容 ${value}'
},
{
title: '${label}-B',
body: '选项卡内容 ${value}'
}
]
}
]
};

View File

@ -2,7 +2,13 @@ import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {Action, Schema, SchemaNode} from '../types';
import find from 'lodash/find';
import {isVisible, autobind, isDisabled} from '../utils/helper';
import {
isVisible,
autobind,
isDisabled,
isObject,
createObject
} from '../utils/helper';
import findIndex from 'lodash/findIndex';
import {Tabs as CTabs, Tab} from '../components/Tabs';
import {ClassNamesFn} from '../theme';
@ -14,6 +20,7 @@ import {
} from '../Schema';
import {ActionSchema} from './Action';
import {filter} from '../utils/tpl';
import {resolveVariable} from '../utils/tpl-builtin';
export interface TabSchema extends Omit<BaseSchema, 'type'> {
/**
@ -72,8 +79,16 @@ export interface TabSchema extends Omit<BaseSchema, 'type'> {
export interface TabsSchema extends BaseSchema {
type: 'tabs';
/**
* source
*/
tabs: Array<TabSchema>;
/**
*
*/
source?: string;
/**
*
*/
@ -292,7 +307,6 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
classnames: cx,
classPrefix: ns,
contentClassName,
tabs,
tabRender,
className,
render,
@ -300,14 +314,96 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
mode: dMode,
tabsMode,
mountOnEnter,
unmountOnExit
unmountOnExit,
source,
value
} = this.props;
if (!Array.isArray(tabs)) {
const mode = tabsMode || dMode;
const arr =
typeof value !== 'undefined'
? isObject(value)
? Object.keys(value).map(key => ({
key: key,
value: value[key]
}))
: Array.isArray(value)
? value
: []
: resolveVariable(source, data);
let tabs = this.props.tabs;
if (!tabs) {
return null;
}
const mode = tabsMode || dMode;
tabs = Array.isArray(tabs) ? tabs : [tabs];
let children: Array<JSX.Element | null> = [];
if (Array.isArray(arr)) {
arr.forEach((value, index) => {
const ctx = createObject(
data,
isObject(value) ? {index, ...value} : {item: value, index}
);
children.push(
...tabs.map((tab, tabIndex) =>
isVisible(tab, ctx) ? (
<Tab
{...(tab as any)}
title={filter(tab.title, ctx)}
disabled={isDisabled(tab, ctx)}
key={`${index * 1000 + tabIndex}`}
eventKey={index * 1000 + tabIndex}
mountOnEnter={mountOnEnter}
unmountOnExit={
typeof tab.reload === 'boolean'
? tab.reload
: typeof tab.unmountOnExit === 'boolean'
? tab.unmountOnExit
: unmountOnExit
}
>
{render(
`item/${index}/${tabIndex}`,
tab.tab || tab.body || '',
{
data: ctx
}
)}
</Tab>
) : null
)
);
});
} else {
children = tabs.map((tab, index) =>
isVisible(tab, data) ? (
<Tab
{...(tab as any)}
title={filter(tab.title, data)}
disabled={isDisabled(tab, data)}
key={index}
eventKey={tab.hash || index}
mountOnEnter={mountOnEnter}
unmountOnExit={
typeof tab.reload === 'boolean'
? tab.reload
: typeof tab.unmountOnExit === 'boolean'
? tab.unmountOnExit
: unmountOnExit
}
>
{this.renderTab
? this.renderTab(tab, this.props, index)
: tabRender
? tabRender(tab, this.props, index)
: render(`tab/${index}`, tab.tab || tab.body || '')}
</Tab>
) : null
);
}
return (
<CTabs
@ -320,31 +416,7 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
activeKey={this.state.activeKey}
toolbar={this.renderToolbar()}
>
{tabs.map((tab, index) =>
isVisible(tab, data) ? (
<Tab
{...(tab as any)}
title={filter(tab.title, data)}
disabled={isDisabled(tab, data)}
key={index}
eventKey={tab.hash || index}
mountOnEnter={mountOnEnter}
unmountOnExit={
typeof tab.reload === 'boolean'
? tab.reload
: typeof tab.unmountOnExit === 'boolean'
? tab.unmountOnExit
: unmountOnExit
}
>
{this.renderTab
? this.renderTab(tab, this.props, index)
: tabRender
? tabRender(tab, this.props, index)
: render(`tab/${index}`, tab.tab || tab.body || '')}
</Tab>
) : null
)}
{children}
</CTabs>
);
}