diff --git a/docs/zh-CN/components/tabs.md b/docs/zh-CN/components/tabs.md index 21d0cbe6f..67163e617 100755 --- a/docs/zh-CN/components/tabs.md +++ b/docs/zh-CN/components/tabs.md @@ -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 标题 | diff --git a/examples/components/Example.tsx b/examples/components/Example.tsx index 88874f4a8..4ce571c3f 100644 --- a/examples/components/Example.tsx +++ b/examples/components/Example.tsx @@ -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', diff --git a/examples/components/Tabs/Dynamic.jsx b/examples/components/Tabs/Dynamic.jsx new file mode 100644 index 000000000..0561a9cc0 --- /dev/null +++ b/examples/components/Tabs/Dynamic.jsx @@ -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}' + } + ] + } + ] +}; diff --git a/src/renderers/Tabs.tsx b/src/renderers/Tabs.tsx index fa0f1d502..0a7556ef1 100644 --- a/src/renderers/Tabs.tsx +++ b/src/renderers/Tabs.tsx @@ -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 { /** @@ -72,8 +79,16 @@ export interface TabSchema extends Omit { export interface TabsSchema extends BaseSchema { type: 'tabs'; + /** + * 选项卡成员。当配置了 source 时,选项卡成员,将会根据目标数据进行重复。 + */ tabs: Array; + /** + * 关联已有数据,选项卡直接根据目标数据重复。 + */ + source?: string; + /** * 类名 */ @@ -292,7 +307,6 @@ export default class Tabs extends React.Component { classnames: cx, classPrefix: ns, contentClassName, - tabs, tabRender, className, render, @@ -300,14 +314,96 @@ export default class Tabs extends React.Component { 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 = []; + + 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) ? ( + + {render( + `item/${index}/${tabIndex}`, + tab.tab || tab.body || '', + { + data: ctx + } + )} + + ) : null + ) + ); + }); + } else { + children = tabs.map((tab, index) => + isVisible(tab, data) ? ( + + {this.renderTab + ? this.renderTab(tab, this.props, index) + : tabRender + ? tabRender(tab, this.props, index) + : render(`tab/${index}`, tab.tab || tab.body || '')} + + ) : null + ); + } return ( { activeKey={this.state.activeKey} toolbar={this.renderToolbar()} > - {tabs.map((tab, index) => - isVisible(tab, data) ? ( - - {this.renderTab - ? this.renderTab(tab, this.props, index) - : tabRender - ? tabRender(tab, this.props, index) - : render(`tab/${index}`, tab.tab || tab.body || '')} - - ) : null - )} + {children} ); }