feat:富文本和分页组件事件面板新增change事件

This commit is contained in:
wutong 2023-10-26 10:36:37 +08:00 committed by miaoxinyu01
parent e9e2a525a6
commit 4f403475e1
8 changed files with 274 additions and 14 deletions

View File

@ -230,3 +230,12 @@ froala 可以通过设置 buttons 参数来控制显示哪些按钮,默认是
| size | `string` | | 框的大小,可设置为 `md` 或者 `lg` |
| options | `object` | | 需要参考 [tinymce](https://www.tiny.cloud/docs/configure/integration-and-setup/) 或 [froala](https://www.froala.com/wysiwyg-editor/docs/options) 的文档 |
| buttons | `Array<string>` | | froala 专用配置显示的按钮tinymce 可以通过前面的 options 设置 [toolbar](https://www.tiny.cloud/docs/demo/custom-toolbar-button/) 字符串 |
## 事件表
当前组件会对外派发以下事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`或`${event.data.[事件参数名]}`来获取事件产生的数据,详细请查看[事件动作](../../docs/concepts/event-action)。
> `[name]`表示当前组件绑定的名称,即`name`属性,如果没有配置`name`属性,则通过`value`取值。
> | 事件名称 | 事件参数 | 说明 |
> | -------- | ------------------------------------- | ------------------------------------------- |
> | change | `[value]: object` 富文本组件的值<br/> | 富文本值改变时触发 |

View File

@ -67,3 +67,10 @@ order: 73
| showPageInput | `boolean` | false | 是否显示快速跳转输入框 layout 和 showPageInput 都可以控制 |
| disabled | `boolean` | false | 是否禁用 |
| onPageChange | page、perPage 改变时会触发 | (page: number, perPage: number) => void; | 分页改变触发 |
当前组件会对外派发以下事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`或`${event.data.[事件参数名]}`来获取事件产生的数据,详细请查看[事件动作](../../docs/concepts/event-action)。
> `[name]`表示当前组件绑定的名称,即`name`属性,如果没有配置`name`属性,则通过`value`取值。
> | 事件名称 | 事件参数 | 说明 |
> | -------- | ------------------------------------- | ------------------------------------------- |
> | change | `[value]: object` 当前页码的值<br/> | 当前页码值改变时触发 |

View File

@ -2,11 +2,12 @@ import {
BaseEventContext,
getSchemaTpl,
defaultValue,
RendererPluginEvent,
tipedLabel
} from 'amis-editor-core';
import {registerEditorPlugin} from 'amis-editor-core';
import {BasePlugin} from 'amis-editor-core';
import {getEventControlConfig} from '../../renderer/event-control/helper';
import {ValidatorTag} from '../../validator';
const tinymceToolbarsDelimiter = ' ';
@ -183,6 +184,32 @@ export class RichTextControlPlugin extends BasePlugin {
panelTitle = '富文本';
events: RendererPluginEvent[] = [
{
eventName: 'change',
eventLabel: '值变化',
description: '输入内容变化',
dataSchema: [
{
type: 'object',
properties: {
data: {
type: 'object',
title: '数据',
properties: {
value: {
type: 'string',
title: '富文本的值'
}
},
description: '当前数据域,可以通过.字段名读取对应的值'
}
}
}
]
}
];
notRenderFormZone = true;
panelJustify = true;
@ -432,6 +459,16 @@ export class RichTextControlPlugin extends BasePlugin {
getSchemaTpl('style:classNames')
])
]
},
{
title: '事件',
className: 'p-none',
body: [
getSchemaTpl('eventControl', {
name: 'onEvent',
...getEventControlConfig(this.manager, context)
})
]
}
]);
};

View File

@ -1,15 +1,15 @@
import {registerEditorPlugin} from 'amis-editor-core';
import {
BasePlugin,
RegionConfig,
BaseEventContext,
tipedLabel
tipedLabel,
defaultValue,
getSchemaTpl,
RendererPluginEvent,
registerEditorPlugin
} from 'amis-editor-core';
import {ValidatorTag} from '../validator';
import {getEventControlConfig} from '../renderer/event-control/helper';
import {RendererPluginEvent} from 'amis-editor-core';
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
export class PaginationPlugin extends BasePlugin {
static id = 'PaginationPlugin';
@ -49,6 +49,32 @@ export class PaginationPlugin extends BasePlugin {
};
panelTitle = '分页器';
events: RendererPluginEvent[] = [
{
eventName: 'change',
eventLabel: '值变化',
description: '输入内容变化',
dataSchema: [
{
type: 'object',
properties: {
data: {
type: 'object',
title: '数据',
properties: {
value: {
type: 'string',
title: '当前页码值'
}
},
description: '当前数据域,可以通过.字段名读取对应的值'
}
}
}
]
}
];
panelJustify = true;
panelBodyCreator = (context: BaseEventContext) => {

View File

@ -5,7 +5,7 @@
*/
import React from 'react';
import isInteger from 'lodash/isInteger';
import {localeable, LocaleProps} from 'amis-core';
import {localeable, LocaleProps, resolveEventData} from 'amis-core';
import {themeable, ThemeProps} from 'amis-core';
import {autobind} from 'amis-core';
import {Icon} from './icons';
@ -93,7 +93,8 @@ export interface BasicPaginationProps {
*/
popOverContainerSelector?: string;
onPageChange?: (page: number, perPage?: number) => void;
onPageChange?: (page: number, perPage?: number, dir?: string) => void;
dispatchEvent?: Function;
}
export interface PaginationProps
extends BasicPaginationProps,
@ -139,13 +140,22 @@ export class Pagination extends React.Component<
}
}
handlePageNumChange(page: number, perPage?: number) {
const {disabled, onPageChange} = this.props;
async handlePageNumChange(page: number, perPage?: number, dir?: string) {
const {disabled, onPageChange, dispatchEvent} = this.props;
const _page = isNaN(Number(page)) || Number(page) < 1 ? 1 : page;
if (disabled) {
return;
}
onPageChange?.(isNaN(Number(page)) || Number(page) < 1 ? 1 : page, perPage);
const rendererEvent = await dispatchEvent?.(
'change',
resolveEventData(this.props, {_page})
);
if (rendererEvent?.prevented) {
return;
}
onPageChange?.(_page, perPage, dir);
}
/**

View File

@ -0,0 +1,159 @@
import {fireEvent, render} from '@testing-library/react';
import '../../../src';
import {render as amisRender} from '../../../src';
import {makeEnv, wait} from '../../helper';
test('pagination: pageNum change event', async () => {
const mockFn = jest.fn();
const pageChange = jest.fn();
const {container} = render(
amisRender(
{
type: 'pagination',
layout: 'total,perPage,pager,go',
mode: 'normal',
activePage: 2,
lastPage: 99999,
total: 999,
perPage: 10,
maxButtons: 7,
showPerPage: true,
perPageAvailable: [10, 20, 50, 100],
showPageInput: true,
disabled: false,
id: 'u:1bf323bc4dbd',
onPageChange: pageChange,
onEvent: {
change: {
weight: 0,
actions: [
{
actionType: 'custom',
script: mockFn
}
]
}
}
},
{},
makeEnv({})
)
);
// 当前页码改变
const prev = container.querySelector('.cxd-Pagination-prev')!;
fireEvent.click(prev); // 上一页
await wait(100);
expect(mockFn).toBeCalledTimes(1);
await wait(200);
expect(pageChange).toBeCalled();
expect(pageChange.mock.calls[0]).toEqual([1, 10]);
const next = container.querySelector('.cxd-Pagination-next')!;
fireEvent.click(next); // 下一页
await wait(300);
expect(mockFn).toBeCalledTimes(2);
await wait(200);
expect(pageChange).toBeCalled();
expect(pageChange.mock.calls[1]).toEqual([3, 10]);
const go = container.querySelector('.cxd-Pagination-inputGroup')!;
fireEvent.change(go.querySelector('.cxd-Pagination-inputGroup-input')!, {
target: {value: 9}
});
await wait(400);
fireEvent.click(go.querySelector('.cxd-Pagination-inputGroup-right')!); // 输入后点击go
await wait(500);
expect(mockFn).toBeCalledTimes(3);
await wait(200);
expect(pageChange).toBeCalled();
expect(pageChange.mock.calls[2]).toEqual([9, 10]);
function getPagerItem() {
const pager = container.querySelectorAll(
'.cxd-Pagination > .cxd-Pagination-pager-item'
);
return pager[3];
}
fireEvent.click(getPagerItem()!); // 点击页码切换
await wait(600);
expect(mockFn).toBeCalledTimes(4);
await wait(200);
expect(pageChange).toBeCalled();
expect(pageChange.mock.calls[3]).toEqual([4, 10]);
});
test('pagination: prevent pageNum change event ', async () => {
const mockFn = jest.fn();
const pageChange = jest.fn();
const {container} = render(
amisRender(
{
type: 'pagination',
layout: 'total,perPage,pager,go',
mode: 'normal',
activePage: 2,
lastPage: 99999,
total: 999,
perPage: 10,
maxButtons: 7,
showPerPage: true,
perPageAvailable: [10, 20, 50, 100],
showPageInput: true,
disabled: false,
id: 'u:1bf323bc4dbd',
onPageChange: pageChange,
onEvent: {
change: {
weight: 0,
actions: [
{
actionType: 'custom',
preventDefault: true, // 阻止事件默认行为
script: mockFn
}
]
}
}
},
{},
makeEnv({})
)
);
// 当前页码改变
const prev = container.querySelector('.cxd-Pagination-prev')!;
fireEvent.click(prev); // 上一页
await wait(100);
expect(mockFn).toBeCalledTimes(1);
await wait(200);
expect(pageChange).not.toBeCalled();
const next = container.querySelector('.cxd-Pagination-next')!;
fireEvent.click(next); // 下一页
await wait(300);
expect(mockFn).toBeCalledTimes(2);
await wait(200);
expect(pageChange).not.toBeCalled();
const go = container.querySelector('.cxd-Pagination-inputGroup')!;
fireEvent.change(go.querySelector('.cxd-Pagination-inputGroup-input')!, {
target: {value: 9}
});
await wait(400);
fireEvent.click(go.querySelector('.cxd-Pagination-inputGroup-right')!); // 输入后点击go
await wait(500);
expect(mockFn).toBeCalledTimes(3);
await wait(200);
expect(pageChange).not.toBeCalled();
function getPagerItem() {
const pager = container.querySelectorAll(
'.cxd-Pagination > .cxd-Pagination-pager-item'
);
return pager[3];
}
fireEvent.click(getPagerItem()!); // 点击页码切换
await wait(600);
expect(mockFn).toBeCalledTimes(4);
await wait(200);
expect(pageChange).not.toBeCalled();
});

View File

@ -117,8 +117,12 @@ test('Renderer:Pagination with simple mode', async () => {
expect(next).not.toHaveClass('is-disabled');
fireEvent.click(next);
await wait(500);
expect(pageChange).toBeCalled();
expect(pageChange.mock.calls[0]).toEqual([3, 10]);
await wait(200);
expect(pageChange.mock.calls[0]).toEqual([3, 10, 'forward']);
rerender(
amisRender(

View File

@ -5,6 +5,7 @@ import {
FormBaseControl,
buildApi,
qsstringify,
resolveEventData,
autobind
} from 'amis-core';
import cx from 'classnames';
@ -252,17 +253,24 @@ export default class RichTextControl extends React.Component<
});
}
handleChange(
async handleChange(
value: any,
submitOnChange?: boolean,
changeImmediately?: boolean
) {
const {onChange, disabled} = this.props;
const {onChange, disabled, dispatchEvent} = this.props;
if (disabled) {
return;
}
const rendererEvent = await dispatchEvent(
'change',
resolveEventData(this.props, {value})
);
if (rendererEvent?.prevented) {
return;
}
onChange?.(value, submitOnChange, changeImmediately);
}