From dfb9a738baabd448a6277d61e1898b49fe5bae4e Mon Sep 17 00:00:00 2001 From: hsm-lv <80095014+hsm-lv@users.noreply.github.com> Date: Mon, 14 Nov 2022 09:28:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E9=83=A8=E5=88=86=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81init=E4=BA=8B=E4=BB=B6&=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=80=89=E9=A1=B9=E7=BB=84=E4=BB=B6=E6=94=AF=E6=8C=81selectedI?= =?UTF-8?q?tems=E5=8F=82=E6=95=B0=20(#5700)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:部分组件支持didMount事件&部分选项组件支持selectedItems参数 * feat:部分组件支持didMount事件&部分选项组件支持selectedItems参数 * feat:部分组件支持初始化事件&部分选项组件支持selectedItems参数 * feat:部分组件支持初始化事件&部分选项组件支持selectedItems参数 * feat:部分组件支持初始化事件&部分选项组件支持selectedItems参数 --- docs/zh-CN/components/app.md | 10 +++++- docs/zh-CN/components/chart.md | 9 ++++- docs/zh-CN/components/form/index.md | 24 ++++++------- docs/zh-CN/components/form/input-tag.md | 10 +++--- docs/zh-CN/components/form/radios.md | 6 ++-- docs/zh-CN/components/form/select.md | 16 ++++----- docs/zh-CN/components/page.md | 9 ++--- docs/zh-CN/components/service.md | 9 ++--- packages/amis-core/src/SchemaRenderer.tsx | 9 +++-- packages/amis-core/src/utils/filter-schema.ts | 2 +- .../amis/__tests__/renderers/Page.test.tsx | 4 +++ packages/amis/src/renderers/App.tsx | 8 +++++ packages/amis/src/renderers/Chart.tsx | 10 ++++-- packages/amis/src/renderers/Form/InputTag.tsx | 19 +++++++---- packages/amis/src/renderers/Form/Radios.tsx | 12 ++++--- packages/amis/src/renderers/Form/Select.tsx | 10 ++++-- packages/amis/src/renderers/Page.tsx | 34 +++++++++++++------ packages/amis/src/renderers/Service.tsx | 9 ++++- 18 files changed, 139 insertions(+), 71 deletions(-) diff --git a/docs/zh-CN/components/app.md b/docs/zh-CN/components/app.md index 3d6a168b0..f026f7723 100644 --- a/docs/zh-CN/components/app.md +++ b/docs/zh-CN/components/app.md @@ -38,7 +38,7 @@ order: 99 } ] } - ], + ] ... } ``` @@ -71,6 +71,14 @@ order: 99 - `visible` 有些页面可能不想出现在菜单中,可以配置成 `false`,另外带参数的路由无需配置,直接就是不可见的。 - `className` 菜单类名。 +## 事件表 + +当前组件会对外派发以下事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`来获取事件产生的数据(`< 2.3.2 及以下版本 为 ${event.data.[事件参数名]}`),详细请查看[事件动作](../../docs/concepts/event-action)。 + +| 事件名称 | 事件参数 | 说明 | +| -------- | -------- | --------------------------------------------------- | +| init | - | 组件实例被创建并插入 DOM 中时触发。2.4.1 及以上版本 | + ## 动作表 | 动作名称 | 动作配置 | 说明 | diff --git a/docs/zh-CN/components/chart.md b/docs/zh-CN/components/chart.md index eb13e9b5c..d90006035 100755 --- a/docs/zh-CN/components/chart.md +++ b/docs/zh-CN/components/chart.md @@ -663,7 +663,14 @@ echarts 的 config 一般是静态配置的,支持简单的数据映射。如 > 2.4.1 及以上版本 -当前组件会对外派发`click`、`mouseover`、`legendselectchanged`事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`来获取事件产生的数据,详细请查看[事件动作](../../docs/concepts/event-action)。事件参数提供通用的字段,可以查看[ECharst 事件与行为文档](https://echarts.apache.org/handbook/zh/concepts/event/)。 +当前组件会对外派发以下事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`来获取事件产生的数据,详细请查看[事件动作](../../docs/concepts/event-action)。 + +| 事件名称 | 事件参数 | 说明 | +| ------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------- | +| init | - | 组件实例被创建并插入 DOM 中时触发。2.4.1 及以上版本 | +| click | 查看[ECharst 事件与行为文档](https://echarts.apache.org/handbook/zh/concepts/event/) | 鼠标点击时触发 | +| mouseover | 查看[ECharst 事件与行为文档](https://echarts.apache.org/handbook/zh/concepts/event/) | 鼠标悬浮时触发 | +| legendselectchanged | 查看[ECharst 事件与行为文档](https://echarts.apache.org/handbook/zh/concepts/event/) | 切换图例选中状态时触发 | ## 动作表 diff --git a/docs/zh-CN/components/form/index.md b/docs/zh-CN/components/form/index.md index a2e18e509..b15fbdfa5 100755 --- a/docs/zh-CN/components/form/index.md +++ b/docs/zh-CN/components/form/index.md @@ -1443,8 +1443,8 @@ Form 支持轮询初始化接口,步骤如下: | promptPageLeave | `boolean` | `false` | form 还没保存,即将离开页面前是否弹框确认。 | | columnCount | `number` | 0 | 表单项显示为几列 | | inheritData | `boolean` | `true` | 默认表单是采用数据链的形式创建个自己的数据域,表单提交的时候只会发送自己这个数据域的数据,如果希望共用上层数据域可以设置这个属性为 false,这样上层数据域的数据不需要在表单中用隐藏域或者显式映射才能发送了。 | -| static | `boolean` | | `2.4.0` 整个表单静态方式展示,详情请查看[示例页](../../../examples/form/switchDisplay) | -| staticClassName | `string` | | `2.4.0` 表单静态展示时使用的类名 | +| static | `boolean` | | `2.4.0` 整个表单静态方式展示,详情请查看[示例页](../../../examples/form/switchDisplay) | +| staticClassName | `string` | | `2.4.0` 表单静态展示时使用的类名 | ## 事件表 @@ -1465,13 +1465,13 @@ Form 支持轮询初始化接口,步骤如下: 当前组件对外暴露以下特性动作,其他组件可以通过指定`actionType: 动作名称`、`componentId: 该组件id`来触发这些动作,动作配置可以通过`args: {动作配置项名称: xxx}`来配置具体的参数,详细请查看[事件动作](../../docs/concepts/event-action#触发其他组件的动作)。 -| 动作名称 | 动作配置 | 说明 | -| -------- | ------------------------------ | -------------------------- | -| submit | - | 提交表单 | -| reset | - | 重置表单 | -| clear | - | 清空表单 | -| validate | - | 校验表单 | -| reload | - | 刷新(重新加载) | -| setValue | `value: object` 更新的表单数据 | 更新数据,对数据进行 merge | -| static | - | 表单切换为静态展示 | -| nonstatic | - | 表单切换为普通输入态 | +| 动作名称 | 动作配置 | 说明 | +| --------- | ------------------------------ | -------------------------- | +| submit | - | 提交表单 | +| reset | - | 重置表单 | +| clear | - | 清空表单 | +| validate | - | 校验表单 | +| reload | - | 刷新(重新加载) | +| setValue | `value: object` 更新的表单数据 | 更新数据,对数据进行 merge | +| static | - | 表单切换为静态展示 | +| nonstatic | - | 表单切换为普通输入态 | diff --git a/docs/zh-CN/components/form/input-tag.md b/docs/zh-CN/components/form/input-tag.md index 5caab6312..de2c9e6f1 100755 --- a/docs/zh-CN/components/form/input-tag.md +++ b/docs/zh-CN/components/form/input-tag.md @@ -138,11 +138,11 @@ order: 55 > `[name]`表示当前组件绑定的名称,即`name`属性,如果没有配置`name`属性,则通过`value`取值。 -| 事件名称 | 事件参数 | 说明 | -| -------- | -------------------------------------------------------------------- | -------------------- | -| change | `[name]: string` 组件的值 | 选中值变化时触发 | -| blur | `[name]: string` 组件的值
`items: object` \| `object[]` 所有选项 | 输入框失去焦点时触发 | -| focus | `[name]: string` 组件的值
`items: object` \| `object[]` 所有选项 | 输入框获取焦点时触发 | +| 事件名称 | 事件参数 | 说明 | +| -------- | ----------------------------------------------------------------------------------------------------------------- | -------------------- | +| change | `[name]: string` 组件的值(多个以逗号分割)
`selectedItems: Option[]` 选中的项
`items: Option[]` 所有选项 | 选中值变化时触发 | +| blur | `[name]: string` 组件的值
`selectedItems: Option[]` 选中的项
`items: Option[]` 所有选项 | 输入框失去焦点时触发 | +| focus | `[name]: string` 组件的值
`selectedItems: Option[]` 选中的项
`items: Option[]` 所有选项 | 输入框获取焦点时触发 | ## 动作表 diff --git a/docs/zh-CN/components/form/radios.md b/docs/zh-CN/components/form/radios.md index 5e99b61d8..8e3a63cf6 100644 --- a/docs/zh-CN/components/form/radios.md +++ b/docs/zh-CN/components/form/radios.md @@ -256,9 +256,9 @@ api 返回内容需要包含 options 字段 > `[name]`表示当前组件绑定的名称,即`name`属性,如果没有配置`name`属性,则通过`value`取值。 -| 事件名称 | 事件参数 | 说明 | -| -------- | -------------------------------------------------------------------- | ---------------- | -| change | `[name]: string` 组件的值
`items: object` \| `object[]` 选项集合 | 选中值变化时触发 | +| 事件名称 | 事件参数 | 说明 | +| -------- | --------------------------------------------------------------------------------------------- | ---------------- | +| change | `[name]: string` 组件的值
`selectedItems: Option` 选中的项
`items: Option[]` 选项集合 | 选中值变化时触发 | ## 动作表 diff --git a/docs/zh-CN/components/form/select.md b/docs/zh-CN/components/form/select.md index 5615a5108..25766b624 100755 --- a/docs/zh-CN/components/form/select.md +++ b/docs/zh-CN/components/form/select.md @@ -1045,14 +1045,14 @@ leftOptions 动态加载,默认 source 接口是返回 options 部分,而 le > `[name]`表示当前组件绑定的名称,即`name`属性,如果没有配置`name`属性,则通过`value`取值。 -| 事件名称 | 事件参数 | 说明 | -| -------- | -------------------------------------------------------------------------------------------- | -------------------- | -| change | `[name]: string` 组件的值
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 选中值变化时触发 | -| blur | `[name]: string` 组件的值
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 输入框失去焦点时触发 | -| focus | `[name]: string` 组件的值
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 输入框获取焦点时触发 | -| add | `[name]: Option` 新增的选项
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 新增选项提交时触发 | -| edit | `[name]: Option` 编辑的选项
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 编辑选项提交时触发 | -| delete | `[name]: Option` 删除的选项
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 删除选项提交时触发 | +| 事件名称 | 事件参数 | 说明 | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | +| change | `[name]: string` 组件的值
`selectedItems: Option \| Option[]` 选中的项
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 选中值变化时触发 | +| blur | `[name]: string` 组件的值
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 输入框失去焦点时触发 | +| focus | `[name]: string` 组件的值
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 输入框获取焦点时触发 | +| add | `[name]: Option` 新增的选项
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 新增选项提交时触发 | +| edit | `[name]: Option` 编辑的选项
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 编辑选项提交时触发 | +| delete | `[name]: Option` 删除的选项
`items: Option[]` 选项集合(< 2.3.2 及以下版本 为`options`) | 删除选项提交时触发 | ## 动作表 diff --git a/docs/zh-CN/components/page.md b/docs/zh-CN/components/page.md index 377bd3be0..32547672d 100755 --- a/docs/zh-CN/components/page.md +++ b/docs/zh-CN/components/page.md @@ -286,10 +286,11 @@ Page 默认将页面分为几个区域,分别是**内容区(`body`)**、** > `[name]`为当前数据域中的字段名,例如:当前数据域为 {username: 'amis'},则可以通过${username}获取对应的值。 -| 事件名称 | 事件参数 | 说明 | -| ----------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------- | -| inited | `event.data` initApi 远程请求返回的初始化数据
`[name]: any` 当前数据域中指定字段的值 | 远程初始化接口请求成功时触发 | -| pullRefresh | - | 开启下拉刷新后,下拉释放后触发(仅用于移动端) | +| 事件名称 | 事件参数 | 说明 | +| ----------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------- | +| init | - | 组件实例被创建并插入 DOM 中时触发。2.4.1 及以上版本 | +| inited | `event.data` initApi 远程请求返回的初始化数据
`[name]: any` 当前数据域中指定字段的值 | 远程初始化接口请求成功时触发 | +| pullRefresh | - | 开启下拉刷新后,下拉释放后触发(仅用于移动端) | ## 动作表 diff --git a/docs/zh-CN/components/service.md b/docs/zh-CN/components/service.md index d26f613a3..f3d3bc9a9 100755 --- a/docs/zh-CN/components/service.md +++ b/docs/zh-CN/components/service.md @@ -703,10 +703,11 @@ ws.on('connection', function connection(ws) { > `[name]`为当前数据域中的字段名,例如:当前数据域为 {username: 'amis'},则可以通过${username}获取对应的值。 -| 事件名称 | 事件参数 | 说明 | -| ----------------- | ---------------------------------------------------------------------------------------- | ---------------------------------- | -| fetchInited | `event.data` api 远程请求返回的初始化数据
`[name]: any` 当前数据域中指定字段的值 | 远程初始化接口请求成功时触发 | -| fetchSchemaInited | `event.data` schemaApi 远程请求返回的 UI 内容
`[name]: any` 当前数据域中指定字段的值 | 远程 schemaApi UI 内容接口请求成功 | +| 事件名称 | 事件参数 | 说明 | +| ----------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------- | +| init | - | 组件实例被创建并插入 DOM 中时触发。2.4.1 及以上版本 | +| fetchInited | `event.data` api 远程请求返回的初始化数据
`[name]: any` 当前数据域中指定字段的值 | 远程初始化接口请求成功时触发 | +| fetchSchemaInited | `event.data` schemaApi 远程请求返回的 UI 内容
`[name]: any` 当前数据域中指定字段的值 | 远程 schemaApi UI 内容接口请求成功 | ## 动作表 diff --git a/packages/amis-core/src/SchemaRenderer.tsx b/packages/amis-core/src/SchemaRenderer.tsx index e8108bca7..3e135dc83 100644 --- a/packages/amis-core/src/SchemaRenderer.tsx +++ b/packages/amis-core/src/SchemaRenderer.tsx @@ -87,9 +87,7 @@ export class SchemaRenderer extends React.Component { () => `${props.topStore.visibleState[props.schema.id || props.$path]}${ props.topStore.disableState[props.schema.id || props.$path] - }${ - props.topStore.staticState[props.schema.id || props.$path] - }`, + }${props.topStore.staticState[props.schema.id || props.$path]}`, () => this.forceUpdate() ); } @@ -206,9 +204,10 @@ export class SchemaRenderer extends React.Component { async dispatchEvent( e: React.MouseEvent, - data: any + data: any, + renderer?: React.Component // for didmount ): Promise | void> { - return await dispatchEvent(e, this.cRef, this.context, data); + return await dispatchEvent(e, this.cRef || renderer, this.context, data); } renderChild( diff --git a/packages/amis-core/src/utils/filter-schema.ts b/packages/amis-core/src/utils/filter-schema.ts index 744de2509..752e61c49 100644 --- a/packages/amis-core/src/utils/filter-schema.ts +++ b/packages/amis-core/src/utils/filter-schema.ts @@ -17,7 +17,7 @@ import cx from 'classnames'; export function getExprProperties( schema: PlainObject, data: object = {}, - blackList: Array = ['addOn'], + blackList: Array = ['addOn', 'ref'], props?: any ): PlainObject { const exprProps: PlainObject = {}; diff --git a/packages/amis/__tests__/renderers/Page.test.tsx b/packages/amis/__tests__/renderers/Page.test.tsx index a0c9c3888..60df982c9 100644 --- a/packages/amis/__tests__/renderers/Page.test.tsx +++ b/packages/amis/__tests__/renderers/Page.test.tsx @@ -106,7 +106,10 @@ test('Renderer:Page initApi error show Message', async () => { expect( container.querySelector('[data-testid="spinner"]') ).not.toBeInTheDocument(); + + expect(container.querySelector('.cxd-Alert')).toBeInTheDocument(); }); + expect(container).toMatchSnapshot(); }); @@ -1355,6 +1358,7 @@ test('Renderer:Page initApi reload by Form submit', async () => { await waitFor(() => { expect(getByText(/Submit/)).toBeInTheDocument(); + expect(getByText('The variable value is 1')).toBeInTheDocument(); expect( container.querySelector('[data-testid="spinner"]') ).not.toBeInTheDocument(); diff --git a/packages/amis/src/renderers/App.tsx b/packages/amis/src/renderers/App.tsx index 55b7d5321..25229d3bd 100644 --- a/packages/amis/src/renderers/App.tsx +++ b/packages/amis/src/renderers/App.tsx @@ -190,6 +190,14 @@ export default class App extends React.Component { } async componentDidMount() { + const {data, dispatchEvent} = this.props; + + const rendererEvent = await dispatchEvent('init', data, this); + + if (rendererEvent?.prevented) { + return; + } + this.reload(); } diff --git a/packages/amis/src/renderers/Chart.tsx b/packages/amis/src/renderers/Chart.tsx index 423f6e225..9647624b9 100644 --- a/packages/amis/src/renderers/Chart.tsx +++ b/packages/amis/src/renderers/Chart.tsx @@ -236,8 +236,14 @@ export class Chart extends React.Component { props.config && this.renderChart(props.config); } - componentDidMount() { - const {api, data, initFetch, source} = this.props; + async componentDidMount() { + const {api, data, initFetch, source, dispatchEvent} = this.props; + + const rendererEvent = await dispatchEvent('init', data, this); + + if (rendererEvent?.prevented) { + return; + } if (source && isPureVariable(source)) { const ret = resolveVariableAndFilter(source, data, '| raw'); diff --git a/packages/amis/src/renderers/Form/InputTag.tsx b/packages/amis/src/renderers/Form/InputTag.tsx index 9d57fea64..ee3656256 100644 --- a/packages/amis/src/renderers/Form/InputTag.tsx +++ b/packages/amis/src/renderers/Form/InputTag.tsx @@ -273,7 +273,8 @@ export default class TagControl extends React.PureComponent< const newValueRes = this.getValue('push', option); const isPrevented = await this.dispatchEvent('change', { - value: newValueRes + value: newValueRes, + selectedItems: selectedOptions.concat(option) }); isPrevented || onChange(newValueRes); } @@ -287,7 +288,8 @@ export default class TagControl extends React.PureComponent< const newValueRes = this.getValue('normal'); const isPrevented = await this.dispatchEvent('focus', { - value: newValueRes + value: newValueRes, + selectedItems: this.props.selectedOptions }); isPrevented || this.props.onFocus?.(e); } @@ -305,7 +307,8 @@ export default class TagControl extends React.PureComponent< const newValueRes = this.normalizeMergedValue(value); const isPrevented = await this.dispatchEvent('blur', { - value: newValueRes + value: newValueRes, + selectedItems: selectedOptions }); isPrevented || this.props.onBlur?.(e); @@ -353,7 +356,8 @@ export default class TagControl extends React.PureComponent< } const isPrevented = await this.dispatchEvent('change', { - value: newValue + value: newValue, + selectedItems: value }); isPrevented || onChange(newValue); } @@ -369,11 +373,13 @@ export default class TagControl extends React.PureComponent< const {selectedOptions, onChange, delimiter} = this.props; const value = this.state.inputValue.trim(); + const selectedItems = selectedOptions.concat({label: value, value}); if (selectedOptions.length && !value && evt.key == 'Backspace') { const newValueRes = this.getValue('pop'); const isPrevented = await this.dispatchEvent('change', { - value: newValueRes + value: newValueRes, + selectedItems }); isPrevented || onChange(newValueRes); } else if (value && (evt.key === 'Enter' || evt.key === delimiter)) { @@ -382,7 +388,8 @@ export default class TagControl extends React.PureComponent< const newValueRes = this.normalizeMergedValue(value); const isPrevented = await this.dispatchEvent('change', { - value: newValueRes + value: newValueRes, + selectedItems }); if (!this.validateInputValue(value)) { diff --git a/packages/amis/src/renderers/Form/Radios.tsx b/packages/amis/src/renderers/Form/Radios.tsx index c657a9a87..f58da74de 100644 --- a/packages/amis/src/renderers/Form/Radios.tsx +++ b/packages/amis/src/renderers/Form/Radios.tsx @@ -63,11 +63,12 @@ export default class RadiosControl extends React.Component { onChange, dispatchEvent, options, - data + selectedOptions } = this.props; + let value = option; if (option && (joinValues || extractValue)) { - option = option[valueField || 'value']; + value = option[valueField || 'value']; } const rendererEvent = await dispatchEvent( @@ -75,9 +76,10 @@ export default class RadiosControl extends React.Component { resolveEventData( this.props, { - value: option, + value, options, - items: options // 为了保持名字统一 + items: options, // 为了保持名字统一 + selectedItems: option }, 'value' ) @@ -86,7 +88,7 @@ export default class RadiosControl extends React.Component { return; } - onChange && onChange(option); + onChange && onChange(value); } reload() { diff --git a/packages/amis/src/renderers/Form/Select.tsx b/packages/amis/src/renderers/Form/Select.tsx index d0bcc6e97..e0f6bdef6 100644 --- a/packages/amis/src/renderers/Form/Select.tsx +++ b/packages/amis/src/renderers/Form/Select.tsx @@ -251,7 +251,9 @@ export default class SelectControl extends React.Component { async dispatchEvent(eventName: SelectRendererEvent, eventData: any = {}) { const event = 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1); - const {dispatchEvent, options, data} = this.props; + const {dispatchEvent, options, data, multiple, selectedOptions} = + this.props; + // 触发渲染器事件 const rendererEvent = await dispatchEvent( eventName, @@ -262,7 +264,8 @@ export default class SelectControl extends React.Component { items: options, // 为了保持名字统一 value: ['onEdit', 'onDelete'].includes(event) ? eventData - : eventData && eventData.value + : eventData && eventData.value, + selectedItems: multiple ? selectedOptions : selectedOptions[0] }, 'value' ) @@ -293,7 +296,8 @@ export default class SelectControl extends React.Component { { value: newValue, options, - items: options // 为了保持名字统一 + items: options, // 为了保持名字统一 + selectedItems: value }, 'value' ) diff --git a/packages/amis/src/renderers/Page.tsx b/packages/amis/src/renderers/Page.tsx index 764186330..65a3fe805 100644 --- a/packages/amis/src/renderers/Page.tsx +++ b/packages/amis/src/renderers/Page.tsx @@ -376,12 +376,33 @@ export default class Page extends React.Component { } } - componentDidMount() { - const {initApi, initFetch, initFetchOn, store, messages, asideSticky} = - this.props; + async componentDidMount() { + const { + initApi, + initFetch, + initFetchOn, + store, + messages, + asideSticky, + data, + dispatchEvent + } = this.props; this.mounted = true; + if (asideSticky && this.asideInner.current) { + const dom = this.asideInner.current!; + dom.style.cssText += `position: sticky; top: ${ + scrollPosition(dom).top + }px;`; + } + + const rendererEvent = await dispatchEvent('init', data, this); + + if (rendererEvent?.prevented) { + return; + } + if (isEffectiveApi(initApi, store.data, initFetch, initFetchOn)) { store .fetchInitData(initApi, store.data, { @@ -390,13 +411,6 @@ export default class Page extends React.Component { }) .then(this.initInterval); } - - if (asideSticky && this.asideInner.current) { - const dom = this.asideInner.current!; - dom.style.cssText += `position: sticky; top: ${ - scrollPosition(dom).top - }px;`; - } } componentDidUpdate(prevProps: PageProps) { diff --git a/packages/amis/src/renderers/Service.tsx b/packages/amis/src/renderers/Service.tsx index 9772b051e..f1e949f83 100644 --- a/packages/amis/src/renderers/Service.tsx +++ b/packages/amis/src/renderers/Service.tsx @@ -182,8 +182,15 @@ export default class Service extends React.Component { this.dataProviderSetData = this.dataProviderSetData.bind(this); } - componentDidMount() { + async componentDidMount() { + const {data, dispatchEvent} = this.props; this.mounted = true; + const rendererEvent = await dispatchEvent('init', data, this); + + if (rendererEvent?.prevented) { + return; + } + this.initFetch(); }