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, 'eol-last': 0,
'react/no-find-dom-node': 0, 'react/no-find-dom-node': 0,
'no-case-declarations': 0, 'no-case-declarations': 0,
'@typescript-eslint/indent': 0, '@typescript-eslint/indent': 0
"indent": "off",
"@typescript-eslint/indent": ["error", 2]
} }
}; };

View File

@ -71,6 +71,8 @@ export class SettingTopEntry implements SettingEntry {
readonly designer: Designer; readonly designer: Designer;
disposeFunctions: any[] = [];
constructor(readonly editor: IEditor, readonly nodes: Node[]) { constructor(readonly editor: IEditor, readonly nodes: Node[]) {
if (!Array.isArray(nodes) || nodes.length < 1) { if (!Array.isArray(nodes) || nodes.length < 1) {
throw new ReferenceError('nodes should not be empty'); throw new ReferenceError('nodes should not be empty');
@ -85,7 +87,7 @@ export class SettingTopEntry implements SettingEntry {
// clear fields // clear fields
this.setupItems(); this.setupItems();
this.setupEvents(); this.disposeFunctions.push(this.setupEvents());
} }
private setupComponentMeta() { private setupComponentMeta() {
@ -127,7 +129,7 @@ export class SettingTopEntry implements SettingEntry {
} }
private setupEvents() { private setupEvents() {
this.componentMeta?.onMetadataChange(() => { return this.componentMeta?.onMetadataChange(() => {
this.setupItems(); this.setupItems();
}); });
} }
@ -219,6 +221,8 @@ export class SettingTopEntry implements SettingEntry {
this.disposeItems(); this.disposeItems();
this._settingFieldMap = {}; this._settingFieldMap = {};
this.emitter.removeAllListeners(); 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 { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema, PageSchema } from '@ali/lowcode-types';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Project } from '../project'; import { Project } from '../project';
@ -361,6 +361,7 @@ export class DocumentModel {
@action @action
import(schema: RootSchema, checkId = false) { import(schema: RootSchema, checkId = false) {
const drillDownNodeId = this._drillDownNode?.id; const drillDownNodeId = this._drillDownNode?.id;
runWithGlobalEventOff(() => {
// TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除 // TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除
this.nodes.forEach(node => { this.nodes.forEach(node => {
if (node.isRoot()) return; if (node.isRoot()) return;
@ -372,6 +373,7 @@ export class DocumentModel {
if (drillDownNodeId) { if (drillDownNodeId) {
this.drillDown(this.getNode(drillDownNodeId)); this.drillDown(this.getNode(drillDownNodeId));
} }
});
} }
export(stage: TransformStage = TransformStage.Serilize) { export(stage: TransformStage = TransformStage.Serilize) {
@ -699,16 +701,18 @@ export class DocumentModel {
} }
onNodeCreate(func: (node: Node) => void) { onNodeCreate(func: (node: Node) => void) {
this.emitter.on('nodecreate', func); const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('nodecreate', wrappedFunc);
return () => { return () => {
this.emitter.removeListener('nodecreate', func); this.emitter.removeListener('nodecreate', wrappedFunc);
}; };
} }
onNodeDestroy(func: (node: Node) => void) { onNodeDestroy(func: (node: Node) => void) {
this.emitter.on('nodedestroy', func); const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('nodedestroy', wrappedFunc);
return () => { return () => {
this.emitter.removeListener('nodedestroy', func); this.emitter.removeListener('nodedestroy', wrappedFunc);
}; };
} }

View File

@ -1,6 +1,6 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { EventEmitter } from 'events'; 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 { import {
isDOMText, isDOMText,
isJSExpression, isJSExpression,
@ -560,9 +560,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
} }
onVisibleChange(func: (flag: boolean) => any): () => void { onVisibleChange(func: (flag: boolean) => any): () => void {
this.emitter.on('visibleChange', func); const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('visibleChange', wrappedFunc);
return () => { 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 { 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( mergeChildren(
@ -1118,9 +1120,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
} }
onPropChange(func: (info: PropChangeOptions) => void): Function { onPropChange(func: (info: PropChangeOptions) => void): Function {
this.emitter.on('propChange', func); const wrappedFunc = wrapWithEventSwitch(func);
this.emitter.on('propChange', wrappedFunc);
return () => { return () => {
this.emitter.removeListener('propChange', func); this.emitter.removeListener('propChange', wrappedFunc);
}; };
} }
} }

View File

@ -180,7 +180,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"zh_CN": "", "zh_CN": "",
@ -259,7 +259,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"zh_CN": "", "zh_CN": "",
@ -334,7 +334,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"zh_CN": "", "zh_CN": "",
@ -426,7 +426,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"zh_CN": "", "zh_CN": "",
@ -517,7 +517,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"zh_CN": "", "zh_CN": "",
@ -684,7 +684,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"zh_CN": "", "zh_CN": "",
@ -763,7 +763,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"zh_CN": "", "zh_CN": "",
@ -855,7 +855,7 @@ Object {
"labelTextAlign": "right", "labelTextAlign": "right",
"labelTipsIcon": "", "labelTipsIcon": "",
"labelTipsText": Object { "labelTipsText": Object {
"en_US": "", "en_US": null,
"type": "i18n", "type": "i18n",
"use": "zh_CN", "use": "zh_CN",
"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 './obx';
export * from './request'; export * from './request';
export * from './focus-tracker'; export * from './focus-tracker';
export * from './control';

View File

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