diff --git a/docs/zh-CN/components/table.md b/docs/zh-CN/components/table.md
index 873be56d8..238fc85c4 100755
--- a/docs/zh-CN/components/table.md
+++ b/docs/zh-CN/components/table.md
@@ -1872,7 +1872,9 @@ popOver 的其它配置请参考 [popover](./popover)
| columnSearch | `searchName: string` 列搜索列名
`searchValue: string` 列搜索数据 | 点击列搜索时触发 |
| orderChange | `movedItems: item[]` 已排序数据 | 手动拖拽行排序时触发 |
| columnToggled | `columns: item[]` 当前显示的列配置数据 | 点击自定义列时触发 |
-| rowClick | `rowItem: object` 行点击数据 | 点击整行时触发 |
+| rowClick | `item: object` 行点击数据
`index: number` 行索引 | 点击整行时触发 |
+| rowMouseEnter | `item: object` 行移入数据
`index: number` 行索引 | 移入整行时触发 |
+| rowMouseLeave | `item: object` 行移出数据
`index: number` 行索引 | 移出整行时触发 |
### 列配置事件表
diff --git a/examples/components/EventAction/cmpt-event-action/TableEvent.jsx b/examples/components/EventAction/cmpt-event-action/TableEvent.jsx
index 122fc5707..802277387 100644
--- a/examples/components/EventAction/cmpt-event-action/TableEvent.jsx
+++ b/examples/components/EventAction/cmpt-event-action/TableEvent.jsx
@@ -256,7 +256,7 @@ export default {
actionType: 'toast',
args: {
msgType: 'info',
- msg: '行单击数据:${rowItem|json}'
+ msg: '行单击数据:${item|json};行索引:${index}'
}
}
]
diff --git a/packages/amis-editor/src/plugin/Table.tsx b/packages/amis-editor/src/plugin/Table.tsx
index 5b468b908..7b258e894 100644
--- a/packages/amis-editor/src/plugin/Table.tsx
+++ b/packages/amis-editor/src/plugin/Table.tsx
@@ -287,7 +287,7 @@ export class TablePlugin extends BasePlugin {
{
type: 'object',
properties: {
- 'event.data.rowItem': {
+ 'event.data.item': {
type: 'object',
title: '行点击数据'
}
diff --git a/packages/amis-editor/src/plugin/Table2.tsx b/packages/amis-editor/src/plugin/Table2.tsx
index e7ea92a2b..5daf5f9f1 100644
--- a/packages/amis-editor/src/plugin/Table2.tsx
+++ b/packages/amis-editor/src/plugin/Table2.tsx
@@ -279,7 +279,7 @@ export class Table2Plugin extends BasePlugin {
{
type: 'object',
properties: {
- 'event.data.rowItem': {
+ 'event.data.item': {
type: 'object',
title: '行点击数据'
}
diff --git a/packages/amis-ui/src/components/table/index.tsx b/packages/amis-ui/src/components/table/index.tsx
index 4eaf95d02..0f46de180 100644
--- a/packages/amis-ui/src/components/table/index.tsx
+++ b/packages/amis-ui/src/components/table/index.tsx
@@ -1166,13 +1166,20 @@ export class Table extends React.PureComponent {
}
}
- onRowMouseEnter(
+ async onRowMouseEnter(
event: React.ChangeEvent,
record?: any,
rowIndex?: number
) {
const {classnames: cx, onRow} = this.props;
+ if (onRow && onRow.onRowMouseEnter) {
+ const prevented = await onRow.onRowMouseEnter(event, record, rowIndex);
+ if (prevented) {
+ return;
+ }
+ }
+
let parent = event.target;
while (parent && parent.tagName !== 'TR') {
parent = parent.parentElement;
@@ -1191,22 +1198,24 @@ export class Table extends React.PureComponent {
target = target.closest('tr');
}
- this.setState({hoverRow: {target, rowIndex, record}}, () => {
- if (onRow) {
- onRow.onRowMouseEnter &&
- onRow.onRowMouseEnter(event, record, rowIndex);
- }
- });
+ this.setState({hoverRow: {target, rowIndex, record}});
}
}
- onRowMouseLeave(
+ async onRowMouseLeave(
event: React.ChangeEvent,
record?: any,
rowIndex?: number
) {
const {classnames: cx, onRow} = this.props;
+ if (onRow && onRow.onRowMouseLeave) {
+ const prevented = await onRow.onRowMouseLeave(event, record, rowIndex);
+ if (prevented) {
+ return;
+ }
+ }
+
let parent = event.target;
while (parent && parent.tagName !== 'TR') {
parent = parent.parentElement;
@@ -1218,12 +1227,6 @@ export class Table extends React.PureComponent {
td.classList.remove(cx('Table-cell-row-hover'));
}
}
-
- if (record) {
- if (onRow) {
- onRow.onRowMouseLeave && onRow.onRowMouseLeave(event, record, rowIndex);
- }
- }
}
onMouseLeave() {
diff --git a/packages/amis/src/renderers/CRUD.tsx b/packages/amis/src/renderers/CRUD.tsx
index a44ba2696..2c06c1beb 100644
--- a/packages/amis/src/renderers/CRUD.tsx
+++ b/packages/amis/src/renderers/CRUD.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import isEqual from 'lodash/isEqual';
import pickBy from 'lodash/pickBy';
+import omitBy from 'lodash/omitBy';
import {Renderer, RendererProps} from 'amis-core';
import {SchemaNode, Schema, ActionObject, PlainObject} from 'amis-core';
import {CRUDStore, ICRUDStore} from 'amis-core';
@@ -44,6 +45,8 @@ import {ActionSchema} from './Action';
import {CardsSchema} from './Cards';
import {ListSchema} from './List';
import {TableSchema} from './Table';
+import type {TableRendererEvent} from './Table';
+import type {CardsRendererEvent} from './Cards';
import {isPureVariable, resolveVariableAndFilter, parseQuery} from 'amis-core';
import type {PaginationProps} from './Pagination';
@@ -74,6 +77,8 @@ export type CRUDToolbarObject = {
align?: 'left' | 'right';
};
+export type CRUDRendererEvent = TableRendererEvent | CardsRendererEvent;
+
export interface CRUDCommonSchema extends BaseSchema, SpinnerExtraProps {
/**
* 指定为 CRUD 渲染器。
@@ -332,6 +337,19 @@ export interface CRUDProps
pickerMode?: boolean; // 选择模式,用做表单中的选择操作
}
+const INNER_EVENTS: Array = [
+ 'selectedChange',
+ 'columnSort',
+ 'columnFilter',
+ 'columnSearch',
+ 'columnToggled',
+ 'orderChange',
+ 'rowClick',
+ 'rowMouseEnter',
+ 'rowMouseLeave',
+ 'selected'
+];
+
export default class CRUD extends React.Component {
static propsList: Array = [
'bulkActions',
@@ -2230,6 +2248,12 @@ export default class CRUD extends React.Component {
'body',
{
...rest,
+ // 通用事件 例如cus-event 如果直接透传给table 则会被触发2次
+ // 因此只将下层组件table、cards中自定义事件透传下去 否则通过crud配置了也不会执行
+ onEvent: omitBy(
+ onEvent,
+ (event, key: any) => !INNER_EVENTS.includes(key)
+ ),
columns: store.columns ?? rest.columns,
type: mode || 'table'
},
diff --git a/packages/amis/src/renderers/CRUD2.tsx b/packages/amis/src/renderers/CRUD2.tsx
index b76c63a54..f63e78b4e 100644
--- a/packages/amis/src/renderers/CRUD2.tsx
+++ b/packages/amis/src/renderers/CRUD2.tsx
@@ -1,7 +1,6 @@
import React from 'react';
-
+import omitBy from 'lodash/omitBy';
import {Renderer, RendererProps} from 'amis-core';
-import {Action} from '../types';
import {CRUDStore, ICRUDStore} from 'amis-core';
import {
createObject,
@@ -22,6 +21,7 @@ import {evalExpression, filter} from 'amis-core';
import {isEffectiveApi, isApiOutdated} from 'amis-core';
import findIndex from 'lodash/findIndex';
import {Html, SpinnerExtraProps} from 'amis-ui';
+import {Action} from '../types';
import {
BaseSchema,
SchemaApi,
@@ -33,11 +33,13 @@ import {
import {CardsSchema} from './Cards';
import {ListSchema} from './List';
import {TableSchema2} from './Table2';
+import type {Table2RendererEvent} from './Table2';
+import type {CardsRendererEvent} from './Cards';
import {isPureVariable, resolveVariableAndFilter} from 'amis-core';
import {SchemaCollection} from '../Schema';
import upperFirst from 'lodash/upperFirst';
-export type CRUDRendererEvent = 'search';
+export type CRUDRendererEvent = Table2RendererEvent | CardsRendererEvent;
export interface CRUD2CommonSchema extends BaseSchema, SpinnerExtraProps {
/**
@@ -193,6 +195,19 @@ export interface CRUD2Props
pickerMode?: boolean; // 选择模式,用做表单中的选择操作
}
+const INNER_EVENTS: Array = [
+ 'selectedChange',
+ 'columnSort',
+ 'columnFilter',
+ 'columnSearch',
+ 'columnToggled',
+ 'orderChange',
+ 'rowClick',
+ 'rowMouseEnter',
+ 'rowMouseLeave',
+ 'selected'
+];
+
export default class CRUD2 extends React.Component {
static propsList: Array = [
'mode',
@@ -1135,6 +1150,7 @@ export default class CRUD2 extends React.Component {
classnames: cx,
keepItemSelectionOnPageChange,
maxKeepItemSelectionLength,
+ onEvent,
onAction,
popOverContainer,
translate: __,
@@ -1171,6 +1187,12 @@ export default class CRUD2 extends React.Component {
'body',
{
...rest,
+ // 通用事件 例如cus-event 如果直接透传给table 则会被触发2次
+ // 因此只将下层组件table、cards中自定义事件透传下去 否则通过crud配置了也不会执行
+ onEvent: omitBy(
+ onEvent,
+ (event, key: any) => !INNER_EVENTS.includes(key)
+ ),
type: mode,
columns: mode.startsWith('table')
? store.columns || columns
diff --git a/packages/amis/src/renderers/Cards.tsx b/packages/amis/src/renderers/Cards.tsx
index 04517383e..37b563220 100644
--- a/packages/amis/src/renderers/Cards.tsx
+++ b/packages/amis/src/renderers/Cards.tsx
@@ -1,4 +1,4 @@
-import React, {Fragment} from 'react';
+import React from 'react';
import {findDOMNode} from 'react-dom';
import {Renderer, RendererProps} from 'amis-core';
import {SchemaNode, Schema, ActionObject} from 'amis-core';
@@ -10,7 +10,6 @@ import {
getScrollParent,
difference,
ucFirst,
- noop,
autobind,
createObject
} from 'amis-core';
@@ -138,9 +137,9 @@ export interface Column {
type: string;
[propName: string]: any;
}
-
-export type CardsRendererEvent = 'change';
-export type CardsRendererAction = 'check-all';
+// 如果这里的事件调整,对应CRUD里的事件配置也需要同步修改
+export type CardsRendererEvent = 'selected';
+export type CardsRendererAction = 'toggleSelectAll' | 'selectAll' | 'clearAll';
export interface GridProps
extends RendererProps,
diff --git a/packages/amis/src/renderers/Table/TableRow.tsx b/packages/amis/src/renderers/Table/TableRow.tsx
index c5e87c4ca..cb18dee51 100644
--- a/packages/amis/src/renderers/Table/TableRow.tsx
+++ b/packages/amis/src/renderers/Table/TableRow.tsx
@@ -1,6 +1,5 @@
import {observer} from 'mobx-react';
import React from 'react';
-import uniq from 'lodash/uniq';
import type {IColumn, IRow} from 'amis-core/lib/store/table';
import {RendererProps} from 'amis-core';
import {Action} from '../Action';
@@ -35,6 +34,31 @@ export class TableRow extends React.Component {
this.handleQuickChange = this.handleQuickChange.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleItemClick = this.handleItemClick.bind(this);
+ this.handleMouseEnter = this.handleMouseEnter.bind(this);
+ this.handleMouseLeave = this.handleMouseLeave.bind(this);
+ }
+
+ handleMouseEnter(e: React.MouseEvent) {
+ const {item, itemIndex, data, dispatchEvent} = this.props;
+
+ dispatchEvent(
+ 'rowMouseEnter',
+ createObject(data, {
+ item: item?.data,
+ index: itemIndex
+ })
+ );
+ }
+
+ handleMouseLeave(e: React.MouseEvent) {
+ const {item, itemIndex, data, dispatchEvent} = this.props;
+ dispatchEvent(
+ 'rowMouseLeave',
+ createObject(data, {
+ item: item?.data,
+ index: itemIndex
+ })
+ );
}
// 定义点击一行的行为,通过 itemAction配置
@@ -43,13 +67,22 @@ export class TableRow extends React.Component {
return;
}
- const {itemAction, onAction, item, data, dispatchEvent, onCheck} =
- this.props;
+ const {
+ itemAction,
+ onAction,
+ item,
+ itemIndex,
+ data,
+ dispatchEvent,
+ onCheck
+ } = this.props;
const rendererEvent = await dispatchEvent(
'rowClick',
createObject(data, {
- rowItem: item?.data
+ rowItem: item?.data, // 保留rowItem 可能有用户已经在用 兼容之前的版本
+ item: item?.data,
+ index: itemIndex
})
);
@@ -144,6 +177,8 @@ export class TableRow extends React.Component {
? this.handleItemClick
: undefined
}
+ onMouseEnter={this.handleMouseEnter}
+ onMouseLeave={this.handleMouseLeave}
className={cx(itemClassName, {
'is-hovered': item.isHover,
'is-checked': item.checked,
@@ -210,6 +245,8 @@ export class TableRow extends React.Component {
? this.handleItemClick
: undefined
}
+ onMouseEnter={this.handleMouseEnter}
+ onMouseLeave={this.handleMouseLeave}
data-index={item.depth === 1 ? item.newIndex : undefined}
data-id={item.id}
className={cx(
diff --git a/packages/amis/src/renderers/Table/index.tsx b/packages/amis/src/renderers/Table/index.tsx
index 8a93895ba..bc23b9f53 100644
--- a/packages/amis/src/renderers/Table/index.tsx
+++ b/packages/amis/src/renderers/Table/index.tsx
@@ -400,6 +400,7 @@ export type ExportExcelToolbar = SchemaNode & {
filename?: string;
};
+// 如果这里的事件调整,对应CRUD里的事件配置也需要同步修改
export type TableRendererEvent =
| 'selectedChange'
| 'columnSort'
@@ -407,7 +408,9 @@ export type TableRendererEvent =
| 'columnSearch'
| 'columnToggled'
| 'orderChange'
- | 'rowClick';
+ | 'rowClick'
+ | 'rowMouseEnter'
+ | 'rowMouseLeave';
export type TableRendererAction =
| 'selectAll'
diff --git a/packages/amis/src/renderers/Table2/index.tsx b/packages/amis/src/renderers/Table2/index.tsx
index 8f44ba44e..a14e0557d 100644
--- a/packages/amis/src/renderers/Table2/index.tsx
+++ b/packages/amis/src/renderers/Table2/index.tsx
@@ -368,13 +368,17 @@ export interface TableSchema2 extends BaseSchema {
keepItemSelectionOnPageChange?: boolean;
}
+// 事件调整 对应CRUD2里的事件配置也需要同步修改
export type Table2RendererEvent =
- | 'selected'
+ | 'selectedChange'
| 'columnSort'
| 'columnFilter'
| 'columnSearch'
| 'columnToggled'
- | 'dragOver';
+ | 'orderChange'
+ | 'rowClick'
+ | 'rowMouseEnter'
+ | 'rowMouseLeave';
export type Table2RendererAction =
| 'selectAll'
@@ -1137,11 +1141,11 @@ export default class Table2 extends React.Component {
const rendererEvent = await dispatchEvent(
'rowClick',
- createObject(data, {rowItem})
+ createObject(data, {item: rowItem, index: rowIndex})
);
if (rendererEvent?.prevented) {
- return rendererEvent?.prevented;
+ return;
}
if (rowItem && onRow) {
@@ -1149,6 +1153,50 @@ export default class Table2 extends React.Component {
}
}
+ @autobind
+ async handleRowMouseEnter(
+ event: React.MouseEvent,
+ rowItem: any,
+ rowIndex?: number
+ ) {
+ const {dispatchEvent, data, onRow} = this.props;
+
+ const rendererEvent = await dispatchEvent(
+ 'rowMouseEnter',
+ createObject(data, {item: rowItem, index: rowIndex})
+ );
+
+ if (rendererEvent?.prevented) {
+ return;
+ }
+
+ if (rowItem && onRow) {
+ onRow.onRowMouseEnter && onRow.onRowMouseEnter(event, rowItem, rowIndex);
+ }
+ }
+
+ @autobind
+ async handleRowMouseLeave(
+ event: React.MouseEvent,
+ rowItem: any,
+ rowIndex?: number
+ ) {
+ const {dispatchEvent, data, onRow} = this.props;
+
+ const rendererEvent = await dispatchEvent(
+ 'rowMouseLeave',
+ createObject(data, {item: rowItem, index: rowIndex})
+ );
+
+ if (rendererEvent?.prevented) {
+ return;
+ }
+
+ if (rowItem && onRow) {
+ onRow.onRowMouseLeave && onRow.onRowMouseLeave(event, rowItem, rowIndex);
+ }
+ }
+
@autobind
async handleOrderChange(
oldIndex: number,
@@ -1457,7 +1505,9 @@ export default class Table2 extends React.Component {
keyField={keyField}
onRow={{
...onRow,
- onRowClick: this.handleRowClick
+ onRowClick: this.handleRowClick,
+ onRowMouseEnter: this.handleRowMouseEnter,
+ onRowMouseLeave: this.handleRowMouseLeave
}}
>
);