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
|
||||
import type {JSONSchema7} from 'json-schema';
|
||||
import {ListenerAction} from './actions/Action';
|
||||
import {debounceConfig} from './utils/renderer-event';
|
||||
|
||||
|
||||
export interface Option {
|
||||
/**
|
||||
@ -592,6 +594,7 @@ export interface BaseSchemaWithoutType {
|
||||
[propName: string]: {
|
||||
weight?: number; // 权重
|
||||
actions: ListenerAction[]; // 执行的动作集
|
||||
debounce?: debounceConfig,
|
||||
};
|
||||
};
|
||||
/**
|
||||
|
@ -2,10 +2,19 @@ import {ListenerAction, ListenerContext, runActions} from '../actions/Action';
|
||||
import {RendererProps} from '../factory';
|
||||
import {IScopedContext} from '../Scoped';
|
||||
import {createObject} from './object';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
|
||||
export interface debounceConfig {
|
||||
maxWait?: number;
|
||||
wait?: number;
|
||||
leading?: boolean;
|
||||
trailing?: boolean;
|
||||
}
|
||||
// 事件监听器
|
||||
export interface EventListeners {
|
||||
[propName: string]: {
|
||||
debounce?: debounceConfig,
|
||||
weight?: number; // 权重
|
||||
actions: ListenerAction[]; // 执行的动作集
|
||||
};
|
||||
@ -16,7 +25,8 @@ export interface OnEventProps {
|
||||
onEvent?: {
|
||||
[propName: string]: {
|
||||
weight?: number; // 权重
|
||||
actions: ListenerAction[]; // 执行的动作集
|
||||
actions: ListenerAction[]; // 执行的动作集,
|
||||
debounce?: debounceConfig,
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -26,9 +36,11 @@ export interface RendererEventListener {
|
||||
renderer: React.Component<RendererProps>;
|
||||
type: string;
|
||||
weight: number;
|
||||
debounce: debounceConfig | null,
|
||||
actions: ListenerAction[];
|
||||
executing?: boolean;
|
||||
debounceInstance?: any;
|
||||
}
|
||||
|
||||
// 将事件上下文转成事件对象
|
||||
export type RendererEvent<T, P = any> = {
|
||||
context: T;
|
||||
@ -86,14 +98,28 @@ export const bindEvent = (renderer: any) => {
|
||||
if (listeners) {
|
||||
// 暂存
|
||||
for (let key of Object.keys(listeners)) {
|
||||
const listener = rendererEventListeners.some(
|
||||
const listener = rendererEventListeners.find(
|
||||
(item: RendererEventListener) =>
|
||||
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) {
|
||||
rendererEventListeners.push({
|
||||
renderer,
|
||||
type: key,
|
||||
debounce: listeners[key].debounce || null,
|
||||
weight: listeners[key].weight || 0,
|
||||
actions: listeners[key].actions
|
||||
});
|
||||
@ -118,7 +144,7 @@ export async function dispatchEvent(
|
||||
data: any,
|
||||
broadcast?: RendererEvent<any>
|
||||
): Promise<RendererEvent<any> | void> {
|
||||
let unbindEvent = null;
|
||||
let unbindEvent: (() => void) | null | undefined = null;
|
||||
const eventName = typeof e === 'string' ? e : e.type;
|
||||
|
||||
renderer?.props?.env?.beforeDispatchEvent?.(
|
||||
@ -163,18 +189,46 @@ export async function dispatchEvent(
|
||||
(prev: RendererEventListener, next: RendererEventListener) =>
|
||||
next.weight - prev.weight
|
||||
);
|
||||
|
||||
let executedCount = 0;
|
||||
const checkExecuted = () => {
|
||||
executedCount++;
|
||||
if (executedCount === listeners.length) {
|
||||
unbindEvent?.();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unbindEvent?.();
|
||||
|
||||
return Promise.resolve(rendererEvent);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user