mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-20 07:14:23 +00:00
Merge branch feat/fixLeafScope into develop
Title: fix: 修复部分属性由于清空,丢失问题 & 修复 function 组件静态属性丢失问题 Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/6867485
This commit is contained in:
commit
dc207aef72
@ -85,6 +85,10 @@ export class ComponentMeta {
|
|||||||
return this._isContainer! || this.isRootComponent();
|
return this._isContainer! || this.isRootComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isMinimalRenderUnit(): boolean {
|
||||||
|
return this._isMinimalRenderUnit || false;
|
||||||
|
}
|
||||||
|
|
||||||
private _isModal?: boolean;
|
private _isModal?: boolean;
|
||||||
|
|
||||||
get isModal(): boolean {
|
get isModal(): boolean {
|
||||||
@ -128,6 +132,8 @@ export class ComponentMeta {
|
|||||||
|
|
||||||
private _title?: TitleContent;
|
private _title?: TitleContent;
|
||||||
|
|
||||||
|
private _isMinimalRenderUnit?: boolean;
|
||||||
|
|
||||||
get title(): string | I18nData | ReactElement {
|
get title(): string | I18nData | ReactElement {
|
||||||
// TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。
|
// TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。
|
||||||
// string | i18nData | ReactElement
|
// string | i18nData | ReactElement
|
||||||
@ -220,6 +226,7 @@ export class ComponentMeta {
|
|||||||
this._isModal = !!component.isModal;
|
this._isModal = !!component.isModal;
|
||||||
this._descriptor = component.descriptor;
|
this._descriptor = component.descriptor;
|
||||||
this._rootSelector = component.rootSelector;
|
this._rootSelector = component.rootSelector;
|
||||||
|
this._isMinimalRenderUnit = component.isMinimalRenderUnit;
|
||||||
if (component.nestingRule) {
|
if (component.nestingRule) {
|
||||||
const { parentWhitelist, childWhitelist } = component.nestingRule;
|
const { parentWhitelist, childWhitelist } = component.nestingRule;
|
||||||
this.parentWhitelist = buildFilter(parentWhitelist);
|
this.parentWhitelist = buildFilter(parentWhitelist);
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
@ -1,87 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1" />
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<title>LowCodeEngine Editor DEMO</title>
|
|
||||||
<link rel="shortcut icon" href="./favicon.png" />
|
|
||||||
<link rel="stylesheet" data-name="vs/editor/editor.main" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.21.0/min/vs/editor/editor.main.css"/>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/react/16.9.0/umd/react.development.js"></script>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/react-dom/16.9.0/umd/react-dom.development.js"></script>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js"></script>
|
|
||||||
<script>
|
|
||||||
React.PropTypes = PropTypes;
|
|
||||||
</script>
|
|
||||||
<script src="https://g.alicdn.com/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js"></script>
|
|
||||||
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
|
||||||
<link rel="stylesheet" href="https://unpkg.alibaba-inc.com/@alifd/next@1.20.25/dist/next.min.css" />
|
|
||||||
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.20.25/dist/next.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/rax@1.1.3/dist/rax.js"></script>
|
|
||||||
<!-- <script src="http://192.168.0.106:8000/lc-engine.js"></script> -->
|
|
||||||
<script>
|
|
||||||
var require = { paths: { vs: 'https://g.alicdn.com/code/lib/monaco-editor/0.21.2/min/vs' } };
|
|
||||||
</script>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/monaco-editor/0.21.2/min/vs/loader.min.js"></script>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/monaco-editor/0.21.2/min/vs/editor/editor.main.nls.js"></script>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/monaco-editor/0.21.2/min/vs/editor/editor.main.js"></script>
|
|
||||||
<link rel="stylesheet" href="/css/editor-preset-vision.css" />
|
|
||||||
<script>
|
|
||||||
window.pageConfig = {
|
|
||||||
env: 'release',
|
|
||||||
locale: 'zh_CN',
|
|
||||||
pageType: 'single',
|
|
||||||
deviceType: 'web',
|
|
||||||
appName: '基础包管理后台',
|
|
||||||
appType: 'legao_base_packages',
|
|
||||||
templateType: '',
|
|
||||||
pageId: 'FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V',
|
|
||||||
slug: 'test',
|
|
||||||
appMode: 'back',
|
|
||||||
isAppAdmin: 'y',
|
|
||||||
isSuperAdmin: 'n',
|
|
||||||
isBetaDeveloper: 'n',
|
|
||||||
formType: 'display',
|
|
||||||
title: { en_US: '测试', type: 'i18n', zh_CN: '测试' },
|
|
||||||
urlPrefix: 'https://go.alibaba-inc.com',
|
|
||||||
APIUrlPrefix: 'https://go.alibaba-inc.com',
|
|
||||||
devVersion: '0.1.0', // 这个是子应用的变更 id
|
|
||||||
subAppType: '0.1.0',
|
|
||||||
appKey: 'legao_base_packages',
|
|
||||||
RE_VERSION: '7.1.1',
|
|
||||||
appSource: '',
|
|
||||||
isDomainDefault: 'n',
|
|
||||||
useReleaseBundle: 'n',
|
|
||||||
isDomainPkg: 'n',
|
|
||||||
medusaAppName: '',
|
|
||||||
domainCode: 'kS6SyH',
|
|
||||||
aecp: {
|
|
||||||
mdcDomain: '',
|
|
||||||
projectId: '',
|
|
||||||
appCode: '',
|
|
||||||
},
|
|
||||||
designerConfigs: {},
|
|
||||||
navConfig:
|
|
||||||
'{"appName":{"en_US":"基础包管理后台","key":"","type":"i18n","zh_CN":"基础包管理后台"},"bgColor":"white","data":[{"children":[],"hidden":false,"icon":"","inner":true,"navUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","relateUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","slug":"test","targetNew":false,"title":{"en_US":"测试","type":"i18n","zh_CN":"测试"}}],"isFixed":"y","isFold":"y","isFoldHorizontal":"n","languageChangeUrl":{"en_US":"/common/account/changeAccountLanguage.json","type":"i18n","zh_CN":"/common/account/changeAccountLanguage.json"},"layout":"auto","navStyle":"orange","navTheme":"light","openSubMode":false,"showAppTitle":true,"showCrumb":true,"showIcon":false,"showLanguageChange":true,"showNav":true,"showSearch":"n","singletons":{"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V":{"isFixed":"n","isFold":"n","isFoldHorizontal":"n","showAppTitle":false,"showCrumb":false,"showLanguageChange":false,"showNav":false,"showSearch":"n","singleton":false},"test":{"$ref":"$.singletons.FORM\\-3KYJN7RV\\-DIOD8LLK1WGQ89S7NHA92\\-QJVH497K\\-V"}},"type":"top_fold"}',
|
|
||||||
historyType: 'HASH',
|
|
||||||
isSinglePage: 'n',
|
|
||||||
rhino: 'n',
|
|
||||||
isMiniApp: '',
|
|
||||||
taskId: '',
|
|
||||||
appSchema: 'V5',
|
|
||||||
openSubMode: 'n',
|
|
||||||
};
|
|
||||||
window.g_config = {};
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<!-- lowcode engine globals -->
|
|
||||||
<div id="lce-container"></div>
|
|
||||||
<!-- vision 测试使用
|
|
||||||
|
|
||||||
-->
|
|
||||||
<script src="/js/editor-preset-vision.js"></script>
|
|
||||||
<script src="https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1" />
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<title>LowCodeEngine DEMO</title>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/react/16.9.0/umd/react.development.js"></script>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/react-dom/16.9.0/umd/react-dom.development.js"></script>
|
|
||||||
<script src="https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js"></script>
|
|
||||||
<script> React.PropTypes = PropTypes; </script>
|
|
||||||
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css">
|
|
||||||
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="lce-container"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -29,7 +29,8 @@
|
|||||||
"react-is": "^16.10.1",
|
"react-is": "^16.10.1",
|
||||||
"serialize-javascript": "^1.7.0",
|
"serialize-javascript": "^1.7.0",
|
||||||
"socket.io-client": "^2.2.0",
|
"socket.io-client": "^2.2.0",
|
||||||
"whatwg-fetch": "^3.0.0"
|
"whatwg-fetch": "^3.0.0",
|
||||||
|
"zen-logger": "^1.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@alib/build-scripts": "^0.1.18",
|
"@alib/build-scripts": "^0.1.18",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { cloneEnumerableProperty } from '@ali/lowcode-utils';
|
||||||
import adapter from '../adapter';
|
import adapter from '../adapter';
|
||||||
|
|
||||||
export function compWrapper(Comp: any) {
|
export function compWrapper(Comp: any) {
|
||||||
@ -8,15 +9,16 @@ export function compWrapper(Comp: any) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { forwardRef } = this.props;
|
const { forwardRef, ...rest } = this.props;
|
||||||
|
|
||||||
return createElement(Comp, {
|
return createElement(Comp, {
|
||||||
...this.props,
|
...rest,
|
||||||
ref: forwardRef,
|
ref: forwardRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return forwardRef((props: any, ref: any) => {
|
return cloneEnumerableProperty(forwardRef((props: any, ref: any) => {
|
||||||
return createElement(Wrapper, { ...props, forwardRef: ref });
|
return createElement(Wrapper, { ...props, forwardRef: ref });
|
||||||
});
|
}), Comp);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,16 @@
|
|||||||
import { BuiltinSimulatorHost, Node, PropChangeOptions } from '@ali/lowcode-designer';
|
import { BuiltinSimulatorHost, Node, PropChangeOptions } from '@ali/lowcode-designer';
|
||||||
import { GlobalEvent, TransformStage } from '@ali/lowcode-types';
|
import { GlobalEvent, TransformStage } from '@ali/lowcode-types';
|
||||||
import { isReactComponent } from '@ali/lowcode-utils';
|
import { isReactComponent, cloneEnumerableProperty } from '@ali/lowcode-utils';
|
||||||
import { EngineOptions } from '@ali/lowcode-editor-core';
|
import { EngineOptions } from '@ali/lowcode-editor-core';
|
||||||
import adapter from '../adapter';
|
import adapter from '../adapter';
|
||||||
import * as types from '../types/index';
|
import * as types from '../types/index';
|
||||||
|
|
||||||
const compDefaultPropertyNames = [
|
|
||||||
'$$typeof',
|
|
||||||
'render',
|
|
||||||
'defaultProps',
|
|
||||||
'props',
|
|
||||||
];
|
|
||||||
|
|
||||||
export interface IComponentHocInfo {
|
export interface IComponentHocInfo {
|
||||||
schema: any;
|
schema: any;
|
||||||
baseRenderer: types.IBaseRendererInstance;
|
baseRenderer: types.IBaseRendererInstance;
|
||||||
componentInfo: any;
|
componentInfo: any;
|
||||||
|
scope: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
type DesignMode = Pick<EngineOptions, 'designMode'>['designMode'];
|
type DesignMode = Pick<EngineOptions, 'designMode'>['designMode'];
|
||||||
@ -45,6 +40,7 @@ enum RerenderType {
|
|||||||
ChildChanged = 'ChildChanged',
|
ChildChanged = 'ChildChanged',
|
||||||
PropsChanged = 'PropsChanged',
|
PropsChanged = 'PropsChanged',
|
||||||
VisibleChanged = 'VisibleChanged',
|
VisibleChanged = 'VisibleChanged',
|
||||||
|
MinimalRenderUnit = 'MinimalRenderUnit',
|
||||||
}
|
}
|
||||||
|
|
||||||
// 缓存 Leaf 层组件,防止重新渲染问题
|
// 缓存 Leaf 层组件,防止重新渲染问题
|
||||||
@ -63,6 +59,8 @@ class LeafCache {
|
|||||||
* 订阅事件缓存,导致 rerender 的订阅事件
|
* 订阅事件缓存,导致 rerender 的订阅事件
|
||||||
*/
|
*/
|
||||||
event = new Map();
|
event = new Map();
|
||||||
|
|
||||||
|
ref = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
let cache: LeafCache;
|
let cache: LeafCache;
|
||||||
@ -119,6 +117,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
schema,
|
schema,
|
||||||
baseRenderer,
|
baseRenderer,
|
||||||
componentInfo,
|
componentInfo,
|
||||||
|
scope,
|
||||||
}: IComponentHocInfo) {
|
}: IComponentHocInfo) {
|
||||||
const {
|
const {
|
||||||
__debug,
|
__debug,
|
||||||
@ -152,8 +151,8 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
getNode,
|
getNode,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (curDocumentId && cache.component.has(schema.componentName)) {
|
if (curDocumentId && cache.component.has(schema.id)) {
|
||||||
return cache.component.get(schema.componentName);
|
return cache.component.get(schema.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
class LeafHoc extends Component {
|
class LeafHoc extends Component {
|
||||||
@ -259,9 +258,71 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
setSchemaChangedSymbol?.(true);
|
setSchemaChangedSymbol?.(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get isInWhitelist() {
|
renderUnitInfo: {
|
||||||
// return whitelist.includes(schema.componentName);
|
minimalUnitId?: string,
|
||||||
// }
|
minimalUnitName?: string;
|
||||||
|
singleRender?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
shouldRenderSingleNode(): boolean {
|
||||||
|
if (!this.renderUnitInfo) {
|
||||||
|
this.getRenderUnitInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderUnitInfo = this.renderUnitInfo;
|
||||||
|
|
||||||
|
if (renderUnitInfo.singleRender) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ref = cache.ref.get(renderUnitInfo.minimalUnitId);
|
||||||
|
|
||||||
|
if (!ref) {
|
||||||
|
__debug('Cant find minimalRenderUnit ref! This make rerender!');
|
||||||
|
container.rerender();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
__debug(`${this.leaf?.componentName}(${this.props.componentId}) need render, make its minimalRenderUnit ${renderUnitInfo.minimalUnitName}(${renderUnitInfo.minimalUnitId})`);
|
||||||
|
ref.makeUnitRender();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRenderUnitInfo(leaf = this.leaf) {
|
||||||
|
if (leaf?.isRoot()) {
|
||||||
|
this.renderUnitInfo = {
|
||||||
|
singleRender: true,
|
||||||
|
...(this.renderUnitInfo || {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (leaf?.componentMeta.isMinimalRenderUnit) {
|
||||||
|
this.renderUnitInfo = {
|
||||||
|
minimalUnitId: leaf.id,
|
||||||
|
minimalUnitName: leaf.componentName,
|
||||||
|
singleRender: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (leaf?.parent) {
|
||||||
|
this.getRenderUnitInfo(leaf.parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeUnitRender() {
|
||||||
|
this.beforeRender(RerenderType.MinimalRenderUnit);
|
||||||
|
const nextProps = getProps(this.leaf?.export?.(TransformStage.Render) as types.ISchema, scope, Comp, componentInfo);
|
||||||
|
const children = getChildren(this.leaf?.export?.(TransformStage.Render) as types.ISchema, scope, Comp);
|
||||||
|
const nextState = {
|
||||||
|
nextProps,
|
||||||
|
nodeChildren: children,
|
||||||
|
childrenInState: true,
|
||||||
|
};
|
||||||
|
if ('children' in nextProps) {
|
||||||
|
nextState.nodeChildren = nextProps.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
__debug(`${this.leaf?.componentName}(${this.props.componentId}) MinimalRenderUnit Render!`);
|
||||||
|
this.setState(nextState);
|
||||||
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps: any) {
|
componentWillReceiveProps(nextProps: any) {
|
||||||
let { _leaf, componentId } = nextProps;
|
let { _leaf, componentId } = nextProps;
|
||||||
@ -291,14 +352,10 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
const dispose = leaf?.onPropChange?.((propChangeInfo: PropChangeOptions) => {
|
const dispose = leaf?.onPropChange?.((propChangeInfo: PropChangeOptions) => {
|
||||||
const {
|
const {
|
||||||
key,
|
key,
|
||||||
|
newValue = null,
|
||||||
} = propChangeInfo;
|
} = propChangeInfo;
|
||||||
const node = leaf;
|
const node = leaf;
|
||||||
|
|
||||||
// if (this.isInWhitelist) {
|
|
||||||
// container.rerender();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 如果循坏条件变化,从根节点重新渲染
|
// 如果循坏条件变化,从根节点重新渲染
|
||||||
// 目前多层循坏无法判断需要从哪一层开始渲染,故先粗暴解决
|
// 目前多层循坏无法判断需要从哪一层开始渲染,故先粗暴解决
|
||||||
if (key === '___loop___') {
|
if (key === '___loop___') {
|
||||||
@ -306,15 +363,24 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
container.rerender();
|
container.rerender();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.shouldRenderSingleNode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.beforeRender(RerenderType.PropsChanged);
|
this.beforeRender(RerenderType.PropsChanged);
|
||||||
__debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange event`);
|
const nodeProps = getProps(node?.export?.(TransformStage.Render) as types.ISchema, scope, Comp, componentInfo);
|
||||||
const nextProps = getProps(node?.export?.(TransformStage.Render) as types.ISchema, Comp, componentInfo);
|
const preNodeProps = this.state.nodeProps;
|
||||||
this.setState(nextProps.children ? {
|
const newNodeProps = {
|
||||||
nodeChildren: nextProps.children,
|
...preNodeProps,
|
||||||
nodeProps: nextProps,
|
[key as string]: newValue,
|
||||||
|
...nodeProps,
|
||||||
|
};
|
||||||
|
__debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange event`, newNodeProps);
|
||||||
|
this.setState('children' in nodeProps ? {
|
||||||
|
nodeChildren: nodeProps.children,
|
||||||
|
nodeProps: newNodeProps,
|
||||||
|
childrenInState: true,
|
||||||
} : {
|
} : {
|
||||||
nodeProps: nextProps,
|
nodeProps: newNodeProps,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -330,12 +396,11 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (this.isInWhitelist) {
|
if (!this.shouldRenderSingleNode()) {
|
||||||
// container.rerender();
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
__debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange event`);
|
__debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange(${flag}) event`);
|
||||||
this.beforeRender(RerenderType.VisibleChanged);
|
this.beforeRender(RerenderType.VisibleChanged);
|
||||||
this.setState({
|
this.setState({
|
||||||
visible: flag,
|
visible: flag,
|
||||||
@ -354,16 +419,15 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
type,
|
type,
|
||||||
node,
|
node,
|
||||||
} = param || {};
|
} = param || {};
|
||||||
// if (this.isInWhitelist) {
|
if (!this.shouldRenderSingleNode()) {
|
||||||
// container.rerender();
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node);
|
this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node);
|
||||||
__debug(`${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`);
|
|
||||||
// TODO: 缓存同级其他元素的 children。
|
// TODO: 缓存同级其他元素的 children。
|
||||||
// 缓存二级 children Next 查询筛选组件有问题
|
// 缓存二级 children Next 查询筛选组件有问题
|
||||||
// 缓存一级 children Next Tab 组件有问题
|
// 缓存一级 children Next Tab 组件有问题
|
||||||
const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, Comp); // this.childrenMap
|
const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, scope, Comp); // this.childrenMap
|
||||||
|
__debug(`${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`, nextChild);
|
||||||
this.setState({
|
this.setState({
|
||||||
nodeChildren: nextChild,
|
nodeChildren: nextChild,
|
||||||
childrenInState: true,
|
childrenInState: true,
|
||||||
@ -391,7 +455,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get children(): any {
|
get children(): any {
|
||||||
if (this.state.nodeChildren) {
|
if (this.state.childrenInState) {
|
||||||
return this.state.nodeChildren;
|
return this.state.nodeChildren;
|
||||||
}
|
}
|
||||||
if (this.props.children && !Array.isArray(this.props.children)) {
|
if (this.props.children && !Array.isArray(this.props.children)) {
|
||||||
@ -413,7 +477,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ref,
|
forwardedRef,
|
||||||
...rest
|
...rest
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@ -422,33 +486,27 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
|
|||||||
...(this.state.nodeProps || {}),
|
...(this.state.nodeProps || {}),
|
||||||
children: [],
|
children: [],
|
||||||
__id: this.props.componentId,
|
__id: this.props.componentId,
|
||||||
ref: this.props.forwardedRef,
|
ref: forwardedRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
return engine.createElement(Comp, compProps, this.hasChildren ? this.children : null);
|
return engine.createElement(Comp, compProps, this.hasChildren ? this.children : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LeafWrapper = forwardRef((props: any, ref: any) => (
|
let LeafWrapper = forwardRef((props: any, ref: any) => (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
<LeafHoc {...props} forwardedRef={ref} />
|
<LeafHoc
|
||||||
|
{...props}
|
||||||
|
forwardedRef={ref}
|
||||||
|
ref={(_ref: any) => cache.ref.set(props.componentId, _ref)}
|
||||||
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
if (typeof Comp === 'object') {
|
LeafWrapper = cloneEnumerableProperty(LeafWrapper, Comp);
|
||||||
const compExtraPropertyNames = Object.getOwnPropertyNames(Comp).filter(d => !compDefaultPropertyNames.includes(d));
|
|
||||||
|
|
||||||
__debug(`${schema.componentName} extra property names: ${compExtraPropertyNames.join(',')}`);
|
|
||||||
|
|
||||||
compExtraPropertyNames.forEach((d: string) => {
|
|
||||||
(LeafWrapper as any)[d] = Comp[d];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
LeafWrapper.displayName = (Comp as any).displayName;
|
LeafWrapper.displayName = (Comp as any).displayName;
|
||||||
|
|
||||||
if (curDocumentId) {
|
cache.component.set(schema.id, LeafWrapper);
|
||||||
cache.component.set(schema.componentName, LeafWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
return LeafWrapper;
|
return LeafWrapper;
|
||||||
}
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Debug from 'debug';
|
|
||||||
import { create as createDataSourceEngine } from '@ali/lowcode-datasource-engine/interpret';
|
import { create as createDataSourceEngine } from '@ali/lowcode-datasource-engine/interpret';
|
||||||
import adapter from '../adapter';
|
import adapter from '../adapter';
|
||||||
import divFactory from '../components/Div';
|
import divFactory from '../components/Div';
|
||||||
@ -21,7 +20,7 @@ import {
|
|||||||
transformStringToFunction,
|
transformStringToFunction,
|
||||||
checkPropTypes,
|
checkPropTypes,
|
||||||
getI18n,
|
getI18n,
|
||||||
acceptsRef,
|
canAcceptsRef,
|
||||||
getFileCssName,
|
getFileCssName,
|
||||||
capitalizeFirstLetter,
|
capitalizeFirstLetter,
|
||||||
DataHelper,
|
DataHelper,
|
||||||
@ -31,6 +30,7 @@ import {
|
|||||||
import { IRendererProps, ISchema, IInfo, ComponentModel, IRenderer } from '../types';
|
import { IRendererProps, ISchema, IInfo, ComponentModel, IRenderer } from '../types';
|
||||||
import { compWrapper } from '../hoc';
|
import { compWrapper } from '../hoc';
|
||||||
import { IComponentConstruct, IComponentHoc, leafWrapper } from '../hoc/leaf';
|
import { IComponentConstruct, IComponentHoc, leafWrapper } from '../hoc/leaf';
|
||||||
|
import logger from '../utils/logger';
|
||||||
|
|
||||||
export default function baseRenererFactory() {
|
export default function baseRenererFactory() {
|
||||||
const { BaseRenderer: customBaseRenderer } = adapter.getRenderers();
|
const { BaseRenderer: customBaseRenderer } = adapter.getRenderers();
|
||||||
@ -44,7 +44,6 @@ export default function baseRenererFactory() {
|
|||||||
const VisualDom = visualDomFactory();
|
const VisualDom = visualDomFactory();
|
||||||
const AppContext = contextFactory();
|
const AppContext = contextFactory();
|
||||||
|
|
||||||
const debug = Debug('renderer:base');
|
|
||||||
const DESIGN_MODE = {
|
const DESIGN_MODE = {
|
||||||
EXTEND: 'extend',
|
EXTEND: 'extend',
|
||||||
BORDER: 'border',
|
BORDER: 'border',
|
||||||
@ -71,7 +70,6 @@ export default function baseRenererFactory() {
|
|||||||
this.__beforeInit(props);
|
this.__beforeInit(props);
|
||||||
this.__init(props);
|
this.__init(props);
|
||||||
this.__afterInit(props);
|
this.__afterInit(props);
|
||||||
this.__initDebug();
|
|
||||||
this.__debug(`constructor - ${props?.__schema?.fileName}`);
|
this.__debug(`constructor - ${props?.__schema?.fileName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +86,7 @@ export default function baseRenererFactory() {
|
|||||||
__afterInit(/* props: IRendererProps */) { }
|
__afterInit(/* props: IRendererProps */) { }
|
||||||
|
|
||||||
static getDerivedStateFromProps(props: IRendererProps, state: any) {
|
static getDerivedStateFromProps(props: IRendererProps, state: any) {
|
||||||
debug('getDerivedStateFromProps');
|
logger.log('getDerivedStateFromProps');
|
||||||
const func = props?.__schema?.lifeCycles?.getDerivedStateFromProps;
|
const func = props?.__schema?.lifeCycles?.getDerivedStateFromProps;
|
||||||
|
|
||||||
if (func) {
|
if (func) {
|
||||||
@ -347,34 +345,31 @@ export default function baseRenererFactory() {
|
|||||||
|
|
||||||
__createDom = () => {
|
__createDom = () => {
|
||||||
const { __schema, __ctx, __components = {} } = this.props;
|
const { __schema, __ctx, __components = {} } = this.props;
|
||||||
const self: any = {};
|
const scope: any = {};
|
||||||
self.__proto__ = __ctx || this;
|
scope.__proto__ = __ctx || this;
|
||||||
if (!this._self) {
|
if (!this._self) {
|
||||||
this._self = self;
|
this._self = scope;
|
||||||
}
|
}
|
||||||
const _children = this.getSchemaChildren(__schema);
|
const _children = this.getSchemaChildren(__schema);
|
||||||
let Comp = __components[__schema.componentName];
|
let Comp = __components[__schema.componentName];
|
||||||
|
|
||||||
return this.__createVirtualDom(_children, self, ({
|
if (!Comp) {
|
||||||
|
this.__debug(`${__schema.componentName} is invalid!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.__createVirtualDom(_children, scope, ({
|
||||||
schema: __schema,
|
schema: __schema,
|
||||||
Comp: this.__getHocComp(Comp, __schema),
|
Comp: this.__getHocComp(Comp, __schema, scope),
|
||||||
} as IInfo));
|
} as IInfo));
|
||||||
};
|
};
|
||||||
|
|
||||||
private get self() {
|
|
||||||
const { __ctx } = this.props;
|
|
||||||
const self: any = {};
|
|
||||||
self.__proto__ = __ctx || this;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将模型结构转换成react Element
|
// 将模型结构转换成react Element
|
||||||
// schema 模型结构
|
// schema 模型结构
|
||||||
// self 为每个渲染组件构造的上下文,self是自上而下继承的
|
// self 为每个渲染组件构造的上下文,self是自上而下继承的
|
||||||
// parentInfo 父组件的信息,包含schema和Comp
|
// parentInfo 父组件的信息,包含schema和Comp
|
||||||
// idx 若为循环渲染的循环Index
|
// idx 若为循环渲染的循环Index
|
||||||
__createVirtualDom = (schema: ISchema, self: any, parentInfo: IInfo, idx: string | number = ''): any => {
|
__createVirtualDom = (schema: ISchema, scope: any, parentInfo: IInfo, idx: string | number = ''): any => {
|
||||||
const { engine } = this.context || {};
|
const { engine } = this.context || {};
|
||||||
try {
|
try {
|
||||||
if (!schema) return null;
|
if (!schema) return null;
|
||||||
@ -388,28 +383,28 @@ export default function baseRenererFactory() {
|
|||||||
const { __appHelper: appHelper, __components: components = {} } = this.props || {};
|
const { __appHelper: appHelper, __components: components = {} } = this.props || {};
|
||||||
|
|
||||||
if (isJSExpression(schema)) {
|
if (isJSExpression(schema)) {
|
||||||
return parseExpression(schema, self);
|
return parseExpression(schema, scope);
|
||||||
}
|
}
|
||||||
if (isI18n(schema)) {
|
if (isI18n(schema)) {
|
||||||
return parseI18n(schema, self);
|
return parseI18n(schema, scope);
|
||||||
}
|
}
|
||||||
if (isJSSlot(schema)) {
|
if (isJSSlot(schema)) {
|
||||||
return this.__createVirtualDom(schema.value, self, parentInfo);
|
return this.__createVirtualDom(schema.value, scope, parentInfo);
|
||||||
}
|
}
|
||||||
if (typeof schema === 'string') return schema;
|
if (typeof schema === 'string') return schema;
|
||||||
if (typeof schema === 'number' || typeof schema === 'boolean') {
|
if (typeof schema === 'number' || typeof schema === 'boolean') {
|
||||||
return String(schema);
|
return String(schema);
|
||||||
}
|
}
|
||||||
if (Array.isArray(schema)) {
|
if (Array.isArray(schema)) {
|
||||||
if (schema.length === 1) return this.__createVirtualDom(schema[0], self, parentInfo);
|
if (schema.length === 1) return this.__createVirtualDom(schema[0], scope, parentInfo);
|
||||||
return schema.map((item, idy) => this.__createVirtualDom(item, self, parentInfo, item?.__ctx?.lceKey ? '' : String(idy)));
|
return schema.map((item, idy) => this.__createVirtualDom(item, scope, parentInfo, item?.__ctx?.lceKey ? '' : String(idy)));
|
||||||
}
|
}
|
||||||
// FIXME
|
// FIXME
|
||||||
const _children = this.getSchemaChildren(schema);
|
const _children = this.getSchemaChildren(schema);
|
||||||
// 解析占位组件
|
// 解析占位组件
|
||||||
if (schema.componentName === 'Flagment' && _children) {
|
if (schema.componentName === 'Flagment' && _children) {
|
||||||
const tarChildren = isJSExpression(_children) ? parseExpression(_children, self) : _children;
|
const tarChildren = isJSExpression(_children) ? parseExpression(_children, scope) : _children;
|
||||||
return this.__createVirtualDom(tarChildren, self, parentInfo);
|
return this.__createVirtualDom(tarChildren, scope, parentInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.$$typeof) {
|
if (schema.$$typeof) {
|
||||||
@ -429,26 +424,26 @@ export default function baseRenererFactory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (schema.loop != null) {
|
if (schema.loop != null) {
|
||||||
const loop = parseData(schema.loop, self);
|
const loop = parseData(schema.loop, scope);
|
||||||
if ((Array.isArray(loop) && loop.length > 0) || isJSExpression(loop)) {
|
if ((Array.isArray(loop) && loop.length > 0) || isJSExpression(loop)) {
|
||||||
return this.__createLoopVirtualDom(
|
return this.__createLoopVirtualDom(
|
||||||
{
|
{
|
||||||
...schema,
|
...schema,
|
||||||
loop,
|
loop,
|
||||||
},
|
},
|
||||||
self,
|
scope,
|
||||||
parentInfo,
|
parentInfo,
|
||||||
idx,
|
idx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const condition = schema.condition == null ? true : parseData(schema.condition, self);
|
const condition = schema.condition == null ? true : parseData(schema.condition, scope);
|
||||||
if (!condition) return null;
|
if (!condition) return null;
|
||||||
|
|
||||||
let scopeKey = '';
|
let scopeKey = '';
|
||||||
// 判断组件是否需要生成scope,且只生成一次,挂在this.__compScopes上
|
// 判断组件是否需要生成scope,且只生成一次,挂在this.__compScopes上
|
||||||
if (Comp.generateScope) {
|
if (Comp.generateScope) {
|
||||||
const key = parseExpression(schema.props.key, self);
|
const key = parseExpression(schema.props.key, scope);
|
||||||
if (key) {
|
if (key) {
|
||||||
// 如果组件自己设置key则使用组件自己的key
|
// 如果组件自己设置key则使用组件自己的key
|
||||||
scopeKey = key;
|
scopeKey = key;
|
||||||
@ -469,8 +464,8 @@ export default function baseRenererFactory() {
|
|||||||
// 如果组件有设置scope,需要为组件生成一个新的scope上下文
|
// 如果组件有设置scope,需要为组件生成一个新的scope上下文
|
||||||
if (scopeKey && this.__compScopes[scopeKey]) {
|
if (scopeKey && this.__compScopes[scopeKey]) {
|
||||||
const compSelf = { ...this.__compScopes[scopeKey] };
|
const compSelf = { ...this.__compScopes[scopeKey] };
|
||||||
compSelf.__proto__ = self;
|
compSelf.__proto__ = scope;
|
||||||
self = compSelf;
|
scope = compSelf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 容器类组件的上下文通过props传递,避免context传递带来的嵌套问题
|
// 容器类组件的上下文通过props传递,避免context传递带来的嵌套问题
|
||||||
@ -488,7 +483,7 @@ export default function baseRenererFactory() {
|
|||||||
otherProps.__tag = Math.random();
|
otherProps.__tag = Math.random();
|
||||||
}
|
}
|
||||||
const componentInfo: any = {};
|
const componentInfo: any = {};
|
||||||
const props: any = this.__getComponentProps(schema, Comp, {
|
const props: any = this.__getComponentProps(schema, scope, Comp, {
|
||||||
...componentInfo,
|
...componentInfo,
|
||||||
props: transformArrayToMap(componentInfo.props, 'name'),
|
props: transformArrayToMap(componentInfo.props, 'name'),
|
||||||
}) || {};
|
}) || {};
|
||||||
@ -498,11 +493,12 @@ export default function baseRenererFactory() {
|
|||||||
schema,
|
schema,
|
||||||
componentInfo,
|
componentInfo,
|
||||||
baseRenderer: this,
|
baseRenderer: this,
|
||||||
|
scope,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 对于可以获取到ref的组件做特殊处理
|
// 对于不可以接收到 ref 的组件需要做特殊处理
|
||||||
if (!acceptsRef(Comp)) {
|
if (!canAcceptsRef(Comp)) {
|
||||||
Comp = compWrapper(Comp);
|
Comp = compWrapper(Comp);
|
||||||
components[schema.componentName] = Comp;
|
components[schema.componentName] = Comp;
|
||||||
}
|
}
|
||||||
@ -522,7 +518,7 @@ export default function baseRenererFactory() {
|
|||||||
}
|
}
|
||||||
if (schema?.__ctx?.lceKey) {
|
if (schema?.__ctx?.lceKey) {
|
||||||
if (!isFileSchema(schema)) {
|
if (!isFileSchema(schema)) {
|
||||||
engine?.props?.onCompGetCtx(schema, self);
|
engine?.props?.onCompGetCtx(schema, scope);
|
||||||
}
|
}
|
||||||
props.key = props.key || `${schema.__ctx.lceKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`;
|
props.key = props.key || `${schema.__ctx.lceKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`;
|
||||||
} else if (typeof idx === 'number' && !props.key) {
|
} else if (typeof idx === 'number' && !props.key) {
|
||||||
@ -535,7 +531,7 @@ export default function baseRenererFactory() {
|
|||||||
props.key = props.__id;
|
props.key = props.__id;
|
||||||
}
|
}
|
||||||
|
|
||||||
let child: any = parentInfo.componentChildren || this.__getSchemaChildrenVirtualDom(schema, Comp);
|
let child: any = parentInfo.componentChildren || this.__getSchemaChildrenVirtualDom(schema, scope, Comp);
|
||||||
const renderComp = (props: any) => engine.createElement(Comp, props, child);
|
const renderComp = (props: any) => engine.createElement(Comp, props, child);
|
||||||
// 设计模式下的特殊处理
|
// 设计模式下的特殊处理
|
||||||
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
||||||
@ -568,7 +564,7 @@ export default function baseRenererFactory() {
|
|||||||
return engine.createElement(engine.getFaultComponent(), {
|
return engine.createElement(engine.getFaultComponent(), {
|
||||||
error: e,
|
error: e,
|
||||||
schema,
|
schema,
|
||||||
self,
|
self: scope,
|
||||||
parentInfo,
|
parentInfo,
|
||||||
idx,
|
idx,
|
||||||
});
|
});
|
||||||
@ -594,7 +590,7 @@ export default function baseRenererFactory() {
|
|||||||
.map((d: IComponentHoc) => d.hoc);
|
.map((d: IComponentHoc) => d.hoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
__getSchemaChildrenVirtualDom = (schema: ISchema, Comp: any, childrenMap?: Map<any, any>) => {
|
__getSchemaChildrenVirtualDom = (schema: ISchema, scope: any, Comp: any, childrenMap?: Map<any, any>) => {
|
||||||
let _children = this.getSchemaChildren(schema);
|
let _children = this.getSchemaChildren(schema);
|
||||||
|
|
||||||
let children: any = [];
|
let children: any = [];
|
||||||
@ -605,8 +601,8 @@ export default function baseRenererFactory() {
|
|||||||
|
|
||||||
_children.forEach((_child: any) => {
|
_children.forEach((_child: any) => {
|
||||||
const _childVirtualDom = this.__createVirtualDom(
|
const _childVirtualDom = this.__createVirtualDom(
|
||||||
isJSExpression(_child) ? parseExpression(_child, this.self) : _child,
|
isJSExpression(_child) ? parseExpression(_child, scope) : _child,
|
||||||
this.self,
|
scope,
|
||||||
{
|
{
|
||||||
schema,
|
schema,
|
||||||
Comp,
|
Comp,
|
||||||
@ -625,11 +621,11 @@ export default function baseRenererFactory() {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
__getComponentProps = (schema: ISchema, Comp: any, componentInfo?: any) => {
|
__getComponentProps = (schema: ISchema, scope: any, Comp: any, componentInfo?: any) => {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return this.__parseProps(schema?.props, this.self, '', {
|
return this.__parseProps(schema?.props, scope, '', {
|
||||||
schema,
|
schema,
|
||||||
Comp,
|
Comp,
|
||||||
componentInfo: {
|
componentInfo: {
|
||||||
@ -639,7 +635,7 @@ export default function baseRenererFactory() {
|
|||||||
}) || {};
|
}) || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
__createLoopVirtualDom = (schema: ISchema, self: any, parentInfo: IInfo, idx: number | string) => {
|
__createLoopVirtualDom = (schema: ISchema, scope: any, parentInfo: IInfo, idx: number | string) => {
|
||||||
if (isFileSchema(schema)) {
|
if (isFileSchema(schema)) {
|
||||||
console.warn('file type not support Loop');
|
console.warn('file type not support Loop');
|
||||||
return null;
|
return null;
|
||||||
@ -652,7 +648,7 @@ export default function baseRenererFactory() {
|
|||||||
[itemArg]: item,
|
[itemArg]: item,
|
||||||
[indexArg]: i,
|
[indexArg]: i,
|
||||||
};
|
};
|
||||||
loopSelf.__proto__ = self;
|
loopSelf.__proto__ = scope;
|
||||||
return this.__createVirtualDom(
|
return this.__createVirtualDom(
|
||||||
{
|
{
|
||||||
...schema,
|
...schema,
|
||||||
@ -670,7 +666,7 @@ export default function baseRenererFactory() {
|
|||||||
return engine?.props?.designMode === 'design';
|
return engine?.props?.designMode === 'design';
|
||||||
}
|
}
|
||||||
|
|
||||||
__parseProps = (props: any, self: any, path: string, info: IInfo): any => {
|
__parseProps = (props: any, scope: any, path: string, info: IInfo): any => {
|
||||||
const { schema, Comp, componentInfo = {} } = info;
|
const { schema, Comp, componentInfo = {} } = info;
|
||||||
const propInfo = getValue(componentInfo.props, path);
|
const propInfo = getValue(componentInfo.props, path);
|
||||||
// FIXME! 将这行逻辑外置,解耦,线上环境不要验证参数,调试环境可以有,通过传参自定义
|
// FIXME! 将这行逻辑外置,解耦,线上环境不要验证参数,调试环境可以有,通过传参自定义
|
||||||
@ -683,7 +679,7 @@ export default function baseRenererFactory() {
|
|||||||
|
|
||||||
const parseReactNode = (data: any, params: any) => {
|
const parseReactNode = (data: any, params: any) => {
|
||||||
if (isEmpty(params)) {
|
if (isEmpty(params)) {
|
||||||
return checkProps(this.__createVirtualDom(data, self, ({ schema, Comp } as IInfo)));
|
return checkProps(this.__createVirtualDom(data, scope, ({ schema, Comp } as IInfo)));
|
||||||
}
|
}
|
||||||
return checkProps(function () {
|
return checkProps(function () {
|
||||||
const args: any = {};
|
const args: any = {};
|
||||||
@ -696,8 +692,8 @@ export default function baseRenererFactory() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
args.__proto__ = self;
|
args.__proto__ = scope;
|
||||||
return self.__createVirtualDom(data, args, { schema, Comp });
|
return scope.__createVirtualDom(data, args, { schema, Comp });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -713,7 +709,7 @@ export default function baseRenererFactory() {
|
|||||||
return checkProps(props);
|
return checkProps(props);
|
||||||
}
|
}
|
||||||
if (isJSExpression(props)) {
|
if (isJSExpression(props)) {
|
||||||
props = parseExpression(props, self);
|
props = parseExpression(props, scope);
|
||||||
// 只有当变量解析出来为模型结构的时候才会继续解析
|
// 只有当变量解析出来为模型结构的时候才会继续解析
|
||||||
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
||||||
}
|
}
|
||||||
@ -726,7 +722,7 @@ export default function baseRenererFactory() {
|
|||||||
if (i18nProp) {
|
if (i18nProp) {
|
||||||
props = i18nProp;
|
props = i18nProp;
|
||||||
} else {
|
} else {
|
||||||
return parseI18n(props, self);
|
return parseI18n(props, scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -768,10 +764,10 @@ export default function baseRenererFactory() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (Array.isArray(props)) {
|
if (Array.isArray(props)) {
|
||||||
return checkProps(props.map((item, idx) => this.__parseProps(item, self, path ? `${path}.${idx}` : `${idx}`, info)));
|
return checkProps(props.map((item, idx) => this.__parseProps(item, scope, path ? `${path}.${idx}` : `${idx}`, info)));
|
||||||
}
|
}
|
||||||
if (typeof props === 'function') {
|
if (typeof props === 'function') {
|
||||||
return checkProps(props.bind(self));
|
return checkProps(props.bind(scope));
|
||||||
}
|
}
|
||||||
if (props && typeof props === 'object') {
|
if (props && typeof props === 'object') {
|
||||||
if (props.$$typeof) return checkProps(props);
|
if (props.$$typeof) return checkProps(props);
|
||||||
@ -781,7 +777,7 @@ export default function baseRenererFactory() {
|
|||||||
res[key] = val;
|
res[key] = val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res[key] = this.__parseProps(val, self, path ? `${path}.${key}` : key, info);
|
res[key] = this.__parseProps(val, scope, path ? `${path}.${key}` : key, info);
|
||||||
});
|
});
|
||||||
return checkProps(res);
|
return checkProps(res);
|
||||||
}
|
}
|
||||||
@ -802,15 +798,7 @@ export default function baseRenererFactory() {
|
|||||||
return this.__instanceMap[filedId];
|
return this.__instanceMap[filedId];
|
||||||
}
|
}
|
||||||
|
|
||||||
__initDebug = () => {
|
__debug = logger.log;
|
||||||
this.__logger = Debug(`renderer:${this.__namespace || 'base'}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
__debug = (msg = '') => {
|
|
||||||
if (this.__logger) {
|
|
||||||
this.__logger(`${this.__namespace}.${msg}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
__renderContextProvider = (customProps?: object, children?: any) => {
|
__renderContextProvider = (customProps?: object, children?: any) => {
|
||||||
customProps = customProps || {};
|
customProps = customProps || {};
|
||||||
@ -829,12 +817,13 @@ export default function baseRenererFactory() {
|
|||||||
return createElement(AppContext.Consumer, {}, children);
|
return createElement(AppContext.Consumer, {}, children);
|
||||||
};
|
};
|
||||||
|
|
||||||
__getHocComp(Comp: any, schema: any) {
|
__getHocComp(Comp: any, schema: any, scope: any) {
|
||||||
this.componentHoc.forEach((ComponentConstruct: IComponentConstruct) => {
|
this.componentHoc.forEach((ComponentConstruct: IComponentConstruct) => {
|
||||||
Comp = ComponentConstruct(Comp || Div, {
|
Comp = ComponentConstruct(Comp || Div, {
|
||||||
schema,
|
schema,
|
||||||
componentInfo: {},
|
componentInfo: {},
|
||||||
baseRenderer: this,
|
baseRenderer: this,
|
||||||
|
scope,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -843,8 +832,11 @@ export default function baseRenererFactory() {
|
|||||||
|
|
||||||
__renderComp(Comp: any, ctxProps: object) {
|
__renderComp(Comp: any, ctxProps: object) {
|
||||||
const { __schema } = this.props;
|
const { __schema } = this.props;
|
||||||
Comp = this.__getHocComp(Comp, __schema);
|
const { __ctx } = this.props;
|
||||||
const data = this.__parseProps(__schema?.props, this.self, '', {
|
const scope: any = {};
|
||||||
|
scope.__proto__ = __ctx || this;
|
||||||
|
Comp = this.__getHocComp(Comp, __schema, scope);
|
||||||
|
const data = this.__parseProps(__schema?.props, scope, '', {
|
||||||
schema: __schema,
|
schema: __schema,
|
||||||
Comp,
|
Comp,
|
||||||
componentInfo: {},
|
componentInfo: {},
|
||||||
|
|||||||
@ -141,7 +141,7 @@ export interface IRenderer {
|
|||||||
__createLoopVirtualDom: (schema: any, self: any, parentInfo: IInfo, idx: number | string) => any;
|
__createLoopVirtualDom: (schema: any, self: any, parentInfo: IInfo, idx: number | string) => any;
|
||||||
__parseProps: (props: any, self: any, path: string, info: IInfo) => any;
|
__parseProps: (props: any, self: any, path: string, info: IInfo) => any;
|
||||||
__initDebug: () => void;
|
__initDebug: () => void;
|
||||||
__debug: (msg: string) => void;
|
__debug: (...args: any[]) => void;
|
||||||
__renderContextProvider: (customProps?: object, children?: any) => any;
|
__renderContextProvider: (customProps?: object, children?: any) => any;
|
||||||
__renderContextConsumer: (children: any) => any;
|
__renderContextConsumer: (children: any) => any;
|
||||||
__renderContent: (children: any) => any;
|
__renderContent: (children: any) => any;
|
||||||
|
|||||||
@ -202,8 +202,8 @@ export function getI18n(key: string, values = {}, locale = 'zh-CN', messages = {
|
|||||||
* 判断当前组件是否能够设置ref
|
* 判断当前组件是否能够设置ref
|
||||||
* @param {*} Comp 需要判断的组件
|
* @param {*} Comp 需要判断的组件
|
||||||
*/
|
*/
|
||||||
export function acceptsRef(Comp: any) {
|
export function canAcceptsRef(Comp: any) {
|
||||||
return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState;
|
return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState || Comp._forwardRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
2
packages/renderer-core/src/utils/logger.ts
Normal file
2
packages/renderer-core/src/utils/logger.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import Logger from 'zen-logger';
|
||||||
|
export default new Logger({ level: 'warn', bizName: 'renderer' });
|
||||||
@ -29,6 +29,8 @@ export interface ComponentConfigure {
|
|||||||
descriptor?: string;
|
descriptor?: string;
|
||||||
nestingRule?: NestingRule;
|
nestingRule?: NestingRule;
|
||||||
|
|
||||||
|
isMinimalRenderUnit?: boolean;
|
||||||
|
|
||||||
rootSelector?: string;
|
rootSelector?: string;
|
||||||
// copy, move, remove | *
|
// copy, move, remove | *
|
||||||
disableBehaviors?: string[] | string;
|
disableBehaviors?: string[] | string;
|
||||||
|
|||||||
22
packages/utils/src/clone-enumerable-property.ts
Normal file
22
packages/utils/src/clone-enumerable-property.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
const excludePropertyNames = [
|
||||||
|
'$$typeof',
|
||||||
|
'render',
|
||||||
|
'defaultProps',
|
||||||
|
'props',
|
||||||
|
'length',
|
||||||
|
'prototype',
|
||||||
|
'name',
|
||||||
|
'caller',
|
||||||
|
'callee',
|
||||||
|
'arguments',
|
||||||
|
];
|
||||||
|
|
||||||
|
export function cloneEnumerableProperty(target: any, origin: any) {
|
||||||
|
const compExtraPropertyNames = Object.keys(origin).filter(d => !excludePropertyNames.includes(d));
|
||||||
|
|
||||||
|
compExtraPropertyNames.forEach((d: string) => {
|
||||||
|
(target as any)[d] = origin[d];
|
||||||
|
});
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
@ -23,3 +23,4 @@ export * from './app-helper';
|
|||||||
export * from './misc';
|
export * from './misc';
|
||||||
export * from './schema';
|
export * from './schema';
|
||||||
export * from './node-helper';
|
export * from './node-helper';
|
||||||
|
export * from './clone-enumerable-property';
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { ComponentClass, Component, FunctionComponent, ComponentType, createElement } from 'react';
|
import { ComponentClass, Component, FunctionComponent, ComponentType, createElement } from 'react';
|
||||||
|
import { cloneEnumerableProperty } from './clone-enumerable-property';
|
||||||
|
|
||||||
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
||||||
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
|
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
|
||||||
@ -20,11 +21,12 @@ export function isReactComponent(obj: any): obj is ComponentType<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function wrapReactClass(view: FunctionComponent) {
|
export function wrapReactClass(view: FunctionComponent) {
|
||||||
const ViewComponentClass = class extends Component {
|
let ViewComponentClass = class extends Component {
|
||||||
render() {
|
render() {
|
||||||
return createElement(view, this.props);
|
return createElement(view, this.props);
|
||||||
}
|
}
|
||||||
} as any;
|
} as any;
|
||||||
|
ViewComponentClass = cloneEnumerableProperty(ViewComponentClass, view);
|
||||||
ViewComponentClass.displayName = view.displayName;
|
ViewComponentClass.displayName = view.displayName;
|
||||||
return ViewComponentClass;
|
return ViewComponentClass;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,6 +132,7 @@ export interface OldPrototypeConfig {
|
|||||||
componentName: string; // =>
|
componentName: string; // =>
|
||||||
docUrl?: string; // =>
|
docUrl?: string; // =>
|
||||||
defaultProps?: any; // => ?
|
defaultProps?: any; // => ?
|
||||||
|
isMinimalRenderUnit?: boolean; // => false
|
||||||
/**
|
/**
|
||||||
* extra actions on the outline of current selected node
|
* extra actions on the outline of current selected node
|
||||||
* by default we have: remove / clone
|
* by default we have: remove / clone
|
||||||
@ -702,6 +703,9 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|||||||
devMode,
|
devMode,
|
||||||
schema,
|
schema,
|
||||||
isTopFixed,
|
isTopFixed,
|
||||||
|
|
||||||
|
// render
|
||||||
|
isMinimalRenderUnit,
|
||||||
} = oldConfig;
|
} = oldConfig;
|
||||||
let {
|
let {
|
||||||
canResizing, // resizing
|
canResizing, // resizing
|
||||||
@ -732,6 +736,7 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|||||||
isModal,
|
isModal,
|
||||||
isFloating,
|
isFloating,
|
||||||
descriptor,
|
descriptor,
|
||||||
|
isMinimalRenderUnit,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (canOperating === false) {
|
if (canOperating === false) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user