feat: Avatar组件支持事件动作 Close #3220 (#9272)

* feat: Avatar组件支持事件动作

* ts处理

* feat: Avatar组件支持事件动作

* feat: Avatar组件支持事件动作-补充版本说明

---------

Co-authored-by: zhaojianhui <zhaojianhui@baidu.com>
This commit is contained in:
zhaojianhui 2024-01-03 14:53:20 +08:00 committed by GitHub
parent 6cfa5e0a9f
commit de76135229
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 295 additions and 3 deletions

View File

@ -258,3 +258,84 @@ src、text 都支持变量,可以从上下文中动态获取图片或文字,
| draggable | `boolean` | | 图片是否允许拖动 |
| crossOrigin | `'anonymous'` \| `'use-credentials'` \| `''` | | 图片的 `CORS` 属性设置 |
| onError | `string` | | 图片加载失败的字符串,这个字符串是一个 New Function 内部执行的字符串,参数是 event使用 event.nativeEvent 获取原生 dom 事件),这个字符串需要返回 boolean 值。设置 `"return ture;"` 会在图片加载失败后,使用 `text` 或者 `icon` 代表的信息来进行替换。目前图片加载失败默认是不进行置换。注意:图片加载失败,不包括$获取数据为空情况 |
## 事件表
> 6.1.0 及以上版本
当前组件会对外派发以下事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`或`${event.data.[事件参数名]}`来获取事件产生的数据,详细查看[事件动作](../../docs/concepts/event-action)。
| 事件名称 | 事件参数 | 说明 |
| ---------- | -------- | -------------- |
| click | - | 点击时触发 |
| mouseenter | - | 鼠标移入时触发 |
| mouseleave | - | 鼠标移出时触发 |
### click
鼠标点击。可以尝试通过`${event.context.nativeEvent}`获取鼠标事件对象。
```schema: scope="body"
{
"type": "avatar",
"onEvent": {
"click": {
"actions": [
{
"actionType": "toast",
"args": {
"msgType": "info",
"msg": "${event.context.nativeEvent.type}"
}
}
]
}
}
}
```
### mouseenter
鼠标移入。可以尝试通过`${event.context.nativeEvent}`获取鼠标事件对象。
```schema: scope="body"
{
"type": "avatar",
"onEvent": {
"mouseenter": {
"actions": [
{
"actionType": "toast",
"args": {
"msgType": "info",
"msg": "${event.context.nativeEvent.type}"
}
}
]
}
}
}
```
### mouseleave
鼠标移出。可以尝试通过`${event.context.nativeEvent}`获取鼠标事件对象。
```schema: scope="body"
{
"type": "avatar",
"onEvent": {
"mouseleave": {
"actions": [
{
"actionType": "toast",
"args": {
"msgType": "info",
"msg": "${event.context.nativeEvent.type}"
}
}
]
}
}
}
```

View File

@ -1,10 +1,11 @@
/**
* @file
*/
import {registerEditorPlugin} from 'amis-editor-core';
import {registerEditorPlugin, RendererPluginEvent} from 'amis-editor-core';
import {BaseEventContext, BasePlugin} from 'amis-editor-core';
import {getSchemaTpl, defaultValue} from 'amis-editor-core';
import {tipedLabel} from 'amis-editor-core';
import {getEventControlConfig} from '../renderer/event-control';
const DefaultSize = 40;
const DefaultBorderRadius = 20;
@ -38,6 +39,77 @@ export class AvatarPlugin extends BasePlugin {
borderRadius: DefaultBorderRadius
}
};
// 事件定义
events: RendererPluginEvent[] = [
{
eventName: 'click',
eventLabel: '点击',
description: '点击时触发',
dataSchema: [
{
type: 'object',
properties: {
context: {
type: 'object',
title: '上下文',
properties: {
nativeEvent: {
type: 'object',
title: '鼠标事件对象'
}
}
}
}
}
]
},
{
eventName: 'mouseenter',
eventLabel: '鼠标移入',
description: '鼠标移入时触发',
dataSchema: [
{
type: 'object',
properties: {
context: {
type: 'object',
title: '上下文',
properties: {
nativeEvent: {
type: 'object',
title: '鼠标事件对象'
}
}
}
}
}
]
},
{
eventName: 'mouseleave',
eventLabel: '鼠标移出',
description: '鼠标移出时触发',
dataSchema: [
{
type: 'object',
properties: {
context: {
type: 'object',
title: '上下文',
properties: {
nativeEvent: {
type: 'object',
title: '鼠标事件对象'
}
}
}
}
}
]
}
];
previewSchema: any = {
...this.scaffold
};
@ -294,6 +366,16 @@ export class AvatarPlugin extends BasePlugin {
},
getSchemaTpl('style:classNames', {isFormItem: false})
])
},
{
title: '事件',
className: 'p-none',
body: [
getSchemaTpl('eventControl', {
name: 'onEvent',
...getEventControlConfig(this.manager, context)
})
]
}
]);
};

View File

@ -74,6 +74,21 @@ interface AvatarCmptProps extends ThemeProps {
| React.ReactNode
| Array<React.ReactNode>
| ((props?: any) => React.ReactNode | Array<React.ReactNode>);
/**
*
*/
onClick?: (e: React.MouseEvent) => void;
/**
*
*/
onMouseEnter?: (e: React.MouseEvent) => void;
/**
*
*/
onMouseLeave?: (e: React.MouseEvent) => void;
}
const prefix = 'Avatar--';
@ -169,7 +184,10 @@ export class Avatar extends React.Component<AvatarCmptProps, AvatarState> {
fit,
text,
children,
classnames: cx
classnames: cx,
onClick,
onMouseEnter,
onMouseLeave
} = this.props;
const {scale, hasImg} = this.state;
@ -248,6 +266,9 @@ export class Avatar extends React.Component<AvatarCmptProps, AvatarState> {
<span
className={cx(`Avatar`, className, prefix + shape, sizeClass)}
style={{...sizeStyle, ...style}}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
ref={this.avatarRef}
>
{childrenRender}

View File

@ -0,0 +1,87 @@
import {fireEvent, render, waitFor} from '@testing-library/react';
import '../../../src';
import {render as amisRender} from '../../../src';
import {makeEnv} from '../../helper';
test('EventAction:avatar', async () => {
const notify = jest.fn();
const {getByText, container}: any = render(
amisRender(
{
type: 'page',
data: {
btnDisabled: true,
btnNotDisabled: false
},
body: [
{
type: 'avatar',
text: 'AM',
onEvent: {
click: {
actions: [
{
actionType: 'toast',
args: {
msgType: 'info',
msg: '派发点击事件'
}
}
]
},
mouseenter: {
actions: [
{
actionType: 'toast',
args: {
msgType: 'info',
msg: '派发鼠标移入事件'
}
}
]
},
mouseleave: {
actions: [
{
actionType: 'toast',
args: {
msgType: 'info',
msg: '派发鼠标移出事件'
}
}
]
}
}
}
]
},
{},
makeEnv({
notify
})
)
);
const avatar = container.querySelector('.cxd-Avatar');
fireEvent.click(avatar);
await waitFor(() => {
expect(notify).toHaveBeenCalledWith('info', '派发点击事件', {
msg: '派发点击事件',
msgType: 'info'
});
});
fireEvent.mouseEnter(avatar);
await waitFor(() => {
expect(notify).toHaveBeenCalledWith('info', '派发鼠标移入事件', {
msg: '派发鼠标移入事件',
msgType: 'info'
});
});
fireEvent.mouseLeave(avatar);
await waitFor(() => {
expect(notify).toHaveBeenCalledWith('info', '派发鼠标移出事件', {
msg: '派发鼠标移出事件',
msgType: 'info'
});
});
});

View File

@ -6,7 +6,7 @@ import {Renderer, RendererProps} from 'amis-core';
import {Avatar} from 'amis-ui';
import {BadgeObject, withBadge} from 'amis-ui';
import {BaseSchema, SchemaClassName} from '../Schema';
import {isPureVariable, resolveVariableAndFilter} from 'amis-core';
import {isPureVariable, resolveVariableAndFilter, autobind} from 'amis-core';
export interface AvatarSchema extends BaseSchema {
// 指定类型
@ -90,6 +90,23 @@ export interface AvatarProps
Omit<AvatarSchema, 'type' | 'className'> {}
export class AvatarField extends React.Component<AvatarProps> {
@autobind
handleClick(e: React.MouseEvent<any>) {
const {dispatchEvent, data} = this.props;
dispatchEvent(e, data);
}
@autobind
handleMouseEnter(e: React.MouseEvent<any>) {
const {dispatchEvent, data} = this.props;
dispatchEvent(e, data);
}
@autobind
handleMouseLeave(e: React.MouseEvent<any>) {
const {dispatchEvent, data} = this.props;
dispatchEvent(e, data);
}
render() {
let {
style = {},
@ -147,6 +164,9 @@ export class AvatarField extends React.Component<AvatarProps> {
draggable={draggable}
crossOrigin={crossOrigin}
onError={errHandler}
onClick={this.handleClick}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
/>
);
}
@ -155,5 +175,6 @@ export class AvatarField extends React.Component<AvatarProps> {
@Renderer({
type: 'avatar'
})
// @ts-ignore
@withBadge
export class AvatarFieldRenderer extends AvatarField {}