mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:48:13 +08:00
Tabs 支持 source 关联数据循环 (#1496)
* Tabs 支持 source 关联数据循环 * visibleOn 的判断传参错误
This commit is contained in:
parent
26ef7d0819
commit
a000fa7c94
@ -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 标题 |
|
||||
|
@ -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',
|
||||
|
36
examples/components/Tabs/Dynamic.jsx
Normal file
36
examples/components/Tabs/Dynamic.jsx
Normal 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}'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user