fix: doc import 时临时关闭 Node 相关事件监听

This commit is contained in:
lihao.ylh 2021-09-28 12:38:33 +08:00
parent d846e86472
commit 0f34f2702d
8 changed files with 123 additions and 58 deletions

View File

@ -28,8 +28,6 @@ module.exports = {
'eol-last': 0,
'react/no-find-dom-node': 0,
'no-case-declarations': 0,
'@typescript-eslint/indent': 0,
"indent": "off",
"@typescript-eslint/indent": ["error", 2]
'@typescript-eslint/indent': 0
}
};

View File

@ -71,6 +71,8 @@ export class SettingTopEntry implements SettingEntry {
readonly designer: Designer;
disposeFunctions: any[] = [];
constructor(readonly editor: IEditor, readonly nodes: Node[]) {
if (!Array.isArray(nodes) || nodes.length < 1) {
throw new ReferenceError('nodes should not be empty');
@ -85,7 +87,7 @@ export class SettingTopEntry implements SettingEntry {
// clear fields
this.setupItems();
this.setupEvents();
this.disposeFunctions.push(this.setupEvents());
}
private setupComponentMeta() {
@ -127,7 +129,7 @@ export class SettingTopEntry implements SettingEntry {
}
private setupEvents() {
this.componentMeta?.onMetadataChange(() => {
return this.componentMeta?.onMetadataChange(() => {
this.setupItems();
});
}
@ -219,6 +221,8 @@ export class SettingTopEntry implements SettingEntry {
this.disposeItems();
this._settingFieldMap = {};
this.emitter.removeAllListeners();
this.disposeFunctions.forEach(f => f());
this.disposeFunctions = [];
}

View File

@ -1,4 +1,4 @@
import { computed, makeObservable, obx, action } from '@ali/lowcode-editor-core';
import { computed, makeObservable, obx, action, runWithGlobalEventOff, wrapWithEventSwitch } from '@ali/lowcode-editor-core';
import { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema, PageSchema } from '@ali/lowcode-types';
import { EventEmitter } from 'events';
import { Project } from '../project';
@ -361,17 +361,19 @@ export class DocumentModel {
@action
import(schema: RootSchema, checkId = false) {
const drillDownNodeId = this._drillDownNode?.id;
// TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除
this.nodes.forEach(node => {
if (node.isRoot()) return;
this.internalRemoveAndPurgeNode(node, true);
});
this.rootNode?.import(schema as any, checkId);
runWithGlobalEventOff(() => {
// TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除
this.nodes.forEach(node => {
if (node.isRoot()) return;
this.internalRemoveAndPurgeNode(node, true);
});
this.rootNode?.import(schema as any, checkId);
// todo: select added and active track added
if (drillDownNodeId) {
this.drillDown(this.getNode(drillDownNodeId));
}
// todo: select added and active track added
if (drillDownNodeId) {
this.drillDown(this.getNode(drillDownNodeId));
}
});
}
export(stage: TransformStage = TransformStage.Serilize) {
@ -699,16 +701,18 @@ export class DocumentModel {
}
onNodeCreate(func: (node: Node) => void) {
this.emitter.on('nodecreate', func);
const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('nodecreate', wrappedFunc);
return () => {
this.emitter.removeListener('nodecreate', func);
this.emitter.removeListener('nodecreate', wrappedFunc);
};
}
onNodeDestroy(func: (node: Node) => void) {
this.emitter.on('nodedestroy', func);
const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('nodedestroy', wrappedFunc);
return () => {
this.emitter.removeListener('nodedestroy', func);
this.emitter.removeListener('nodedestroy', wrappedFunc);
};
}

View File

@ -1,6 +1,6 @@
import { ReactElement } from 'react';
import { EventEmitter } from 'events';
import { obx, computed, autorun, makeObservable, runInAction, getObserverTree } from '@ali/lowcode-editor-core';
import { obx, computed, autorun, makeObservable, runInAction, wrapWithEventSwitch } from '@ali/lowcode-editor-core';
import {
isDOMText,
isJSExpression,
@ -560,9 +560,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
}
onVisibleChange(func: (flag: boolean) => any): () => void {
this.emitter.on('visibleChange', func);
const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('visibleChange', wrappedFunc);
return () => {
this.emitter.removeListener('visibleChange', func);
this.emitter.removeListener('visibleChange', wrappedFunc);
};
}
@ -920,7 +921,8 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
}
onChildrenChange(fn: (param?: { type: string, node: Node }) => void): (() => void) | undefined {
return this.children?.onChange(fn);
const wrappedFunc = wrapWithEventSwitch(fn);
return this.children?.onChange(wrappedFunc);
}
mergeChildren(
@ -1118,9 +1120,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
}
onPropChange(func: (info: PropChangeOptions) => void): Function {
this.emitter.on('propChange', func);
const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('propChange', wrappedFunc);
return () => {
this.emitter.removeListener('propChange', func);
this.emitter.removeListener('propChange', wrappedFunc);
};
}
}

View File

@ -180,7 +180,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",
@ -259,7 +259,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",
@ -334,7 +334,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",
@ -426,7 +426,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",
@ -517,7 +517,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",
@ -684,7 +684,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",
@ -763,7 +763,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",
@ -855,7 +855,7 @@ Object {
"labelTextAlign": "right",
"labelTipsIcon": "",
"labelTipsText": Object {
"en_US": "",
"en_US": null,
"type": "i18n",
"use": "zh_CN",
"zh_CN": "",

View File

@ -0,0 +1,30 @@
let globalEventOn = true;
export function setGlobalEventFlag(flag: boolean) {
globalEventOn = flag;
}
export function switchGlobalEventOn() {
setGlobalEventFlag(true);
}
export function switchGlobalEventOff() {
setGlobalEventFlag(false);
}
export function isGlobalEventOn() {
return globalEventOn;
}
export function runWithGlobalEventOff(fn: Function) {
switchGlobalEventOff();
fn();
switchGlobalEventOn();
}
type ListenerFunc = (...args: any[]) => void;
export function wrapWithEventSwitch(fn: ListenerFunc): ListenerFunc {
return (...args: any[]) => {
if (isGlobalEventOn()) fn(...args);
};
}

View File

@ -3,3 +3,4 @@ export * from './monitor';
export * from './obx';
export * from './request';
export * from './focus-tracker';
export * from './control';

View File

@ -90,7 +90,6 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
type?: string;
node?: Node;
} = {};
static displayName = schema.componentName;
disposeFunctions: ((() => void) | Function)[] = [];
@ -140,19 +139,44 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
return whitelist.includes(schema.componentName);
}
static getDerivedStateFromProps(props: any, state: any) {
if (props.__tag === state.__tag) {
componentWillReceiveProps(nextProps: any) {
if (nextProps.__tag === this.state.__tag) {
return null;
}
const { _leaf, __tag, children, ...rest } = nextProps;
if (_leaf && this.leaf && _leaf !== this.leaf) {
this.disposeFunctions.forEach(fn => fn());
this.disposeFunctions = [];
this.initOnChildrenChangeEvent(_leaf);
this.initOnPropsChangeEvent(_leaf);
this.initOnVisibleChangeEvent(_leaf);
}
return {
nodeChildren: props.children,
nodeProps: props.nodeProps,
this.setState({
nodeChildren: children,
nodeProps: rest,
childrenInState: true,
__tag: props.__tag,
};
__tag,
});
}
// static getDerivedStateFromProps(props: any, state: any) {
// if (props.__tag === state.__tag) {
// return null;
// }
// if (props._leaf && this.state.leaf && props._leaf !== this.state.leaf) {
// this.disposeFunctions.forEach(fn => fn());
// }
// return {
// nodeChildren: props.children,
// nodeProps: props.nodeProps,
// childrenInState: true,
// __tag: props.__tag,
// _leaf: props._leaf,
// };
// }
shouldComponentUpdate() {
if (this.isInWhitelist) {
__debug(`${schema.componentName} is in leaf Hoc whitelist`);
@ -164,12 +188,12 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
}
/** 监听参数变化 */
initOnPropsChangeEvent(): void {
const dispose = this.leaf?.onPropChange?.((propChangeInfo: PropChangeOptions) => {
initOnPropsChangeEvent(leaf = this.leaf): void {
const dispose = leaf?.onPropChange?.((propChangeInfo: PropChangeOptions) => {
const {
key,
} = propChangeInfo;
const node = this.leaf;
const node = leaf;
// 如果循坏条件变化,从根节点重新渲染
// 目前多层循坏无法判断需要从哪一层开始渲染,故先粗暴解决
@ -180,7 +204,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
}
this.beforeRender(RerenderType.PropsChanged);
__debug(`${this.leaf?.componentName} component trigger onPropsChange event`);
__debug(`${leaf?.componentName} component trigger onPropsChange event`);
const nextProps = getProps(node?.export?.(TransformStage.Render) as types.ISchema, Comp, componentInfo);
this.setState(nextProps.children ? {
nodeChildren: nextProps.children,
@ -196,13 +220,13 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
/**
*
*/
initOnVisibleChangeEvent() {
const dispose = this.leaf?.onVisibleChange?.((flag: boolean) => {
initOnVisibleChangeEvent(leaf = this.leaf) {
const dispose = leaf?.onVisibleChange?.((flag: boolean) => {
if (this.state.visible === flag) {
return;
}
__debug(`${this.leaf?.componentName} component trigger onVisibleChange event`);
__debug(`${leaf?.componentName} component trigger onVisibleChange event`);
this.beforeRender(RerenderType.VisibleChanged);
this.setState({
visible: flag,
@ -215,15 +239,15 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
/**
* ...
*/
initOnChildrenChangeEvent() {
const dispose = this.leaf?.onChildrenChange?.((param): void => {
initOnChildrenChangeEvent(leaf = this.leaf) {
const dispose = leaf?.onChildrenChange?.((param): void => {
const {
type,
node,
} = param || {};
this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node);
__debug(`${this.leaf} component trigger onChildrenChange event`);
const nextChild = getChildren(this.leaf?.export?.(TransformStage.Render) as types.ISchema, Comp);
__debug(`${leaf} component trigger onChildrenChange event`);
const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, Comp);
this.setState({
nodeChildren: nextChild,
childrenInState: true,
@ -238,15 +262,16 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
}
get hasChildren(): boolean {
let { children } = this.props;
if (this.state.childrenInState) {
return !!this.state.nodeChildren?.length;
children = this.state.nodeChildren;
}
if (Array.isArray(this.props.children)) {
return Boolean(this.props.children && this.props.children.length);
if (Array.isArray(children)) {
return Boolean(children && children.length);
}
return Boolean(this.props.children);
return Boolean(children);
}
get children(): any {
@ -305,4 +330,4 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
LeafWrapper.displayName = (Comp as any).displayName;
return LeafWrapper;
}
}