mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
Merge pull request #5848 from pianruijie/feat/debounce-event
feat: debounce event
This commit is contained in:
commit
b9a2bd819d
@ -1,6 +1,8 @@
|
|||||||
// https://json-schema.org/draft-07/json-schema-release-notes.html
|
// https://json-schema.org/draft-07/json-schema-release-notes.html
|
||||||
import type {JSONSchema7} from 'json-schema';
|
import type {JSONSchema7} from 'json-schema';
|
||||||
import {ListenerAction} from './actions/Action';
|
import {ListenerAction} from './actions/Action';
|
||||||
|
import {debounceConfig} from './utils/renderer-event';
|
||||||
|
|
||||||
|
|
||||||
export interface Option {
|
export interface Option {
|
||||||
/**
|
/**
|
||||||
@ -592,6 +594,7 @@ export interface BaseSchemaWithoutType {
|
|||||||
[propName: string]: {
|
[propName: string]: {
|
||||||
weight?: number; // 权重
|
weight?: number; // 权重
|
||||||
actions: ListenerAction[]; // 执行的动作集
|
actions: ListenerAction[]; // 执行的动作集
|
||||||
|
debounce?: debounceConfig,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
|
@ -2,10 +2,19 @@ import {ListenerAction, ListenerContext, runActions} from '../actions/Action';
|
|||||||
import {RendererProps} from '../factory';
|
import {RendererProps} from '../factory';
|
||||||
import {IScopedContext} from '../Scoped';
|
import {IScopedContext} from '../Scoped';
|
||||||
import {createObject} from './object';
|
import {createObject} from './object';
|
||||||
|
import debounce from 'lodash/debounce';
|
||||||
|
|
||||||
|
|
||||||
|
export interface debounceConfig {
|
||||||
|
maxWait?: number;
|
||||||
|
wait?: number;
|
||||||
|
leading?: boolean;
|
||||||
|
trailing?: boolean;
|
||||||
|
}
|
||||||
// 事件监听器
|
// 事件监听器
|
||||||
export interface EventListeners {
|
export interface EventListeners {
|
||||||
[propName: string]: {
|
[propName: string]: {
|
||||||
|
debounce?: debounceConfig,
|
||||||
weight?: number; // 权重
|
weight?: number; // 权重
|
||||||
actions: ListenerAction[]; // 执行的动作集
|
actions: ListenerAction[]; // 执行的动作集
|
||||||
};
|
};
|
||||||
@ -16,7 +25,8 @@ export interface OnEventProps {
|
|||||||
onEvent?: {
|
onEvent?: {
|
||||||
[propName: string]: {
|
[propName: string]: {
|
||||||
weight?: number; // 权重
|
weight?: number; // 权重
|
||||||
actions: ListenerAction[]; // 执行的动作集
|
actions: ListenerAction[]; // 执行的动作集,
|
||||||
|
debounce?: debounceConfig,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -26,9 +36,11 @@ export interface RendererEventListener {
|
|||||||
renderer: React.Component<RendererProps>;
|
renderer: React.Component<RendererProps>;
|
||||||
type: string;
|
type: string;
|
||||||
weight: number;
|
weight: number;
|
||||||
|
debounce: debounceConfig | null,
|
||||||
actions: ListenerAction[];
|
actions: ListenerAction[];
|
||||||
|
executing?: boolean;
|
||||||
|
debounceInstance?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将事件上下文转成事件对象
|
// 将事件上下文转成事件对象
|
||||||
export type RendererEvent<T, P = any> = {
|
export type RendererEvent<T, P = any> = {
|
||||||
context: T;
|
context: T;
|
||||||
@ -86,14 +98,28 @@ export const bindEvent = (renderer: any) => {
|
|||||||
if (listeners) {
|
if (listeners) {
|
||||||
// 暂存
|
// 暂存
|
||||||
for (let key of Object.keys(listeners)) {
|
for (let key of Object.keys(listeners)) {
|
||||||
const listener = rendererEventListeners.some(
|
const listener = rendererEventListeners.find(
|
||||||
(item: RendererEventListener) =>
|
(item: RendererEventListener) =>
|
||||||
item.renderer === renderer && item.type === key
|
item.renderer === renderer && item.type === key
|
||||||
);
|
);
|
||||||
|
if (listener?.executing) {
|
||||||
|
listener?.debounceInstance?.cancel?.();
|
||||||
|
rendererEventListeners = rendererEventListeners.filter(
|
||||||
|
(item: RendererEventListener) =>
|
||||||
|
!(item.renderer === listener.renderer && item.type === listener.type));
|
||||||
|
rendererEventListeners.push({
|
||||||
|
renderer,
|
||||||
|
type: key,
|
||||||
|
debounce: listener.debounce || null,
|
||||||
|
weight: listener.weight || 0,
|
||||||
|
actions: listener.actions
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!listener) {
|
if (!listener) {
|
||||||
rendererEventListeners.push({
|
rendererEventListeners.push({
|
||||||
renderer,
|
renderer,
|
||||||
type: key,
|
type: key,
|
||||||
|
debounce: listeners[key].debounce || null,
|
||||||
weight: listeners[key].weight || 0,
|
weight: listeners[key].weight || 0,
|
||||||
actions: listeners[key].actions
|
actions: listeners[key].actions
|
||||||
});
|
});
|
||||||
@ -118,7 +144,7 @@ export async function dispatchEvent(
|
|||||||
data: any,
|
data: any,
|
||||||
broadcast?: RendererEvent<any>
|
broadcast?: RendererEvent<any>
|
||||||
): Promise<RendererEvent<any> | void> {
|
): Promise<RendererEvent<any> | void> {
|
||||||
let unbindEvent = null;
|
let unbindEvent: (() => void) | null | undefined = null;
|
||||||
const eventName = typeof e === 'string' ? e : e.type;
|
const eventName = typeof e === 'string' ? e : e.type;
|
||||||
|
|
||||||
renderer?.props?.env?.beforeDispatchEvent?.(
|
renderer?.props?.env?.beforeDispatchEvent?.(
|
||||||
@ -163,18 +189,46 @@ export async function dispatchEvent(
|
|||||||
(prev: RendererEventListener, next: RendererEventListener) =>
|
(prev: RendererEventListener, next: RendererEventListener) =>
|
||||||
next.weight - prev.weight
|
next.weight - prev.weight
|
||||||
);
|
);
|
||||||
|
let executedCount = 0;
|
||||||
|
const checkExecuted = () => {
|
||||||
|
executedCount++;
|
||||||
|
if (executedCount === listeners.length) {
|
||||||
|
unbindEvent?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
for (let listener of listeners) {
|
for (let listener of listeners) {
|
||||||
await runActions(listener.actions, listener.renderer, rendererEvent);
|
const {wait=100, trailing=true, leading=false, maxWait=10000} = listener?.debounce || {};
|
||||||
|
if (listener?.debounce) {
|
||||||
|
const debounced = debounce(
|
||||||
|
async () => {
|
||||||
|
await runActions(listener.actions, listener.renderer, rendererEvent);
|
||||||
|
checkExecuted();
|
||||||
|
},
|
||||||
|
wait,
|
||||||
|
{
|
||||||
|
trailing,
|
||||||
|
leading,
|
||||||
|
maxWait
|
||||||
|
}
|
||||||
|
);
|
||||||
|
rendererEventListeners.forEach(item => {
|
||||||
|
// 找到事件队列中正在执行的事件加上标识,下次待执行队列就会把这个事件过滤掉
|
||||||
|
if (item.renderer === listener.renderer && listener.type === item.type) {
|
||||||
|
item.executing = true;
|
||||||
|
item.debounceInstance = debounced;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
debounced();
|
||||||
|
} else {
|
||||||
|
await runActions(listener.actions, listener.renderer, rendererEvent);
|
||||||
|
checkExecuted();
|
||||||
|
}
|
||||||
|
|
||||||
// 停止后续监听器执行
|
// 停止后续监听器执行
|
||||||
if (rendererEvent.stoped) {
|
if (rendererEvent.stoped) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unbindEvent?.();
|
|
||||||
|
|
||||||
return Promise.resolve(rendererEvent);
|
return Promise.resolve(rendererEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user