From 05995cce5844c7c2d09dfb99509b50b75062594a Mon Sep 17 00:00:00 2001 From: beautiful-boyyy Date: Sun, 4 Aug 2024 23:16:18 +0800 Subject: [PATCH] feat: add dynamicStyle addon --- .../src/transducers/addon-combine.ts | 24 ++- packages/renderer-core/src/hoc/leaf.tsx | 166 +++++++++++------- packages/renderer-core/src/renderer/page.tsx | 22 +++ 3 files changed, 141 insertions(+), 71 deletions(-) diff --git a/packages/editor-skeleton/src/transducers/addon-combine.ts b/packages/editor-skeleton/src/transducers/addon-combine.ts index c2bc2dd4c..98c608d24 100644 --- a/packages/editor-skeleton/src/transducers/addon-combine.ts +++ b/packages/editor-skeleton/src/transducers/addon-combine.ts @@ -82,14 +82,18 @@ export default function ( eventsDefinition.push({ type: 'lifeCycleEvent', title: '生命周期', - list: supportedLifecycles.map((event: any) => (typeof event === 'string' ? { name: event } : event)), + list: supportedLifecycles.map((event: any) => + typeof event === 'string' ? { name: event } : event, + ), }); } if (supports.events) { eventsDefinition.push({ type: 'events', title: '事件', - list: (supports.events || []).map((event: any) => (typeof event === 'string' ? { name: event } : event)), + list: (supports.events || []).map((event: any) => + typeof event === 'string' ? { name: event } : event, + ), }); } // 通用设置 @@ -192,6 +196,16 @@ export default function ( }, }); } + if (supports.dynamicStyle) { + stylesGroup.push({ + name: 'dynamicStyle', + title: { type: 'i18n', 'zh-CN': '动态样式', 'en-US': 'dynamicStyle' }, + setter: 'JsonSetter', + extraProps: { + display: 'block', + }, + }); + } if (stylesGroup.length > 0) { combined.push({ name: '#styles', @@ -334,8 +348,10 @@ export default function ( }, tip: { type: 'i18n', - 'zh-CN': '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助', - 'en-US': 'Used with 「Conditional Rendering」or「Cycle Rendering」, the same principle as the key in the react component, click to view the help', + 'zh-CN': + '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助', + 'en-US': + 'Used with 「Conditional Rendering」or「Cycle Rendering」, the same principle as the key in the react component, click to view the help', }, docUrl: 'https://www.yuque.com/lce/doc/qm75w3', }, diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 2bb3c0b36..31d32c0d9 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -1,5 +1,10 @@ import { INode, IPublicTypePropChangeOptions } from '@alilc/lowcode-designer'; -import { GlobalEvent, IPublicEnumTransformStage, IPublicTypeNodeSchema, IPublicTypeEngineOptions } from '@alilc/lowcode-types'; +import { + GlobalEvent, + IPublicEnumTransformStage, + IPublicTypeNodeSchema, + IPublicTypeEngineOptions, +} from '@alilc/lowcode-types'; import { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils'; import { debounce } from '../utils/common'; import adapter from '../adapter'; @@ -40,7 +45,10 @@ export interface IComponentHoc { hoc: IComponentConstruct; } -export type IComponentConstruct = (Comp: types.IBaseRenderComponent, info: IComponentHocInfo) => types.IGeneralConstructor; +export type IComponentConstruct = ( + Comp: types.IBaseRenderComponent, + info: IComponentHocInfo, +) => types.IGeneralConstructor; interface IProps { _leaf: INode | undefined; @@ -66,7 +74,6 @@ enum RerenderType { // 缓存 Leaf 层组件,防止重新渲染问题 class LeafCache { - /** 组件缓存 */ component = new Map(); @@ -82,24 +89,15 @@ class LeafCache { ref = new Map(); - constructor(public documentId: string, public device: string) { - } + constructor(public documentId: string, public device: string) {} } let cache: LeafCache; /** 部分没有渲染的 node 节点进行兜底处理 or 渲染方式没有渲染 LeafWrapper */ -function initRerenderEvent({ - schema, - __debug, - container, - getNode, -}: any) { +function initRerenderEvent({ schema, __debug, container, getNode }: any) { const leaf = getNode?.(schema.id); - if (!leaf - || cache.event.get(schema.id)?.clear - || leaf === cache.event.get(schema.id) - ) { + if (!leaf || cache.event.get(schema.id)?.clear || leaf === cache.event.get(schema.id)) { return; } cache.event.get(schema.id)?.dispose.forEach((disposeFn: any) => disposeFn && disposeFn()); @@ -114,21 +112,27 @@ function initRerenderEvent({ if (!container.autoRepaintNode) { return; } - __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onPropsChange make rerender`); + __debug( + `${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onPropsChange make rerender`, + ); debounceRerender(); }), leaf?.onChildrenChange?.(() => { if (!container.autoRepaintNode) { return; } - __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onChildrenChange make rerender`); + __debug( + `${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onChildrenChange make rerender`, + ); debounceRerender(); }) as Function, leaf?.onVisibleChange?.(() => { if (!container.autoRepaintNode) { return; } - __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onVisibleChange make rerender`); + __debug( + `${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onVisibleChange make rerender`, + ); debounceRerender(); }), ], @@ -148,12 +152,10 @@ function clearRerenderEvent(id: string): void { } // 给每个组件包裹一个 HOC Leaf,支持组件内部属性变化,自响应渲染 -export function leafWrapper(Comp: types.IBaseRenderComponent, { - schema, - baseRenderer, - componentInfo, - scope, -}: IComponentHocInfo) { +export function leafWrapper( + Comp: types.IBaseRenderComponent, + { schema, baseRenderer, componentInfo, scope }: IComponentHocInfo, +) { const { __debug, __getComponentProps: getProps, @@ -171,13 +173,18 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { const runtime = adapter.getRuntime(); const { forwardRef, createElement } = runtime; const Component = runtime.Component as types.IGeneralConstructor< - IComponentHocProps, IComponentHocState + IComponentHocProps, + IComponentHocState >; const componentCacheId = schema.id; - if (!cache || (curDocumentId && curDocumentId !== cache.documentId) || (curDevice && curDevice !== cache.device)) { - cache?.event.forEach(event => { + if ( + !cache || + (curDocumentId && curDocumentId !== cache.documentId) || + (curDevice && curDevice !== cache.device) + ) { + cache?.event.forEach((event) => { event.dispose?.forEach((disposeFn: any) => disposeFn && disposeFn()); }); cache = new LeafCache(curDocumentId, curDevice); @@ -194,7 +201,11 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { getNode, }); - if (curDocumentId && cache.component.has(componentCacheId) && (cache.component.get(componentCacheId).Comp === Comp)) { + if ( + curDocumentId && + cache.component.has(componentCacheId) && + cache.component.get(componentCacheId).Comp === Comp + ) { return cache.component.get(componentCacheId).LeafWrapper; } @@ -209,7 +220,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { static displayName = schema.componentName; - disposeFunctions: Array<((() => void) | Function)> = []; + disposeFunctions: Array<(() => void) | Function> = []; __component_tag = 'leafWrapper'; @@ -244,7 +255,9 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { constructor(props: IProps, context: any) { super(props, context); // 监听以下事件,当变化时更新自己 - __debug(`${schema.componentName}[${this.props.componentId}] leaf render in SimulatorRendererView`); + __debug( + `${schema.componentName}[${this.props.componentId}] leaf render in SimulatorRendererView`, + ); clearRerenderEvent(componentCacheId); this.curEventLeaf = this.leaf; @@ -266,7 +279,8 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } const endTime = Date.now(); const nodeCount = host?.designer?.currentDocument?.getNodeCount?.(); - const componentName = this.recordInfo.node?.componentName || this.leaf?.componentName || 'UnknownComponent'; + const componentName = + this.recordInfo.node?.componentName || this.leaf?.componentName || 'UnknownComponent'; editor?.eventBus.emit(GlobalEvent.Node.Rerender, { componentName, time: endTime - this.recordInfo.startTime, @@ -297,10 +311,8 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } getDefaultState(nextProps: any) { - const { - hidden = false, - condition = true, - } = nextProps.__inner__ || this.leaf?.export?.(IPublicEnumTransformStage.Render) || {}; + const { hidden = false, condition = true } = + nextProps.__inner__ || this.leaf?.export?.(IPublicEnumTransformStage.Render) || {}; return { nodeChildren: null, childrenInState: false, @@ -317,6 +329,12 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { ...state, __tag: this.props.__tag, }); + let style = state.nodeProps.style ?? {}; + const { dynamicStyle } = state.nodeProps; + if (typeof dynamicStyle === 'object') { + style = { ...style, ...dynamicStyle }; + } + if (style && Object.keys(style).length) state.nodeProps.style = style; super.setState(state); } @@ -348,7 +366,9 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { container?.rerender(); return; } - __debug(`${this.leaf?.componentName}(${this.props.componentId}) need render, make its minimalRenderUnit ${renderUnitInfo.minimalUnitName}(${renderUnitInfo.minimalUnitId})`); + __debug( + `${this.leaf?.componentName}(${this.props.componentId}) need render, make its minimalRenderUnit ${renderUnitInfo.minimalUnitName}(${renderUnitInfo.minimalUnitId})`, + ); ref.makeUnitRender(); } @@ -400,20 +420,14 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { this.curEventLeaf = _leaf; } - const { - visible, - ...resetState - } = this.getDefaultState(nextProps); + const { visible, ...resetState } = this.getDefaultState(nextProps); this.setState(resetState); } /** 监听参数变化 */ initOnPropsChangeEvent(leaf = this.leaf): void { const handlePropsChange = debounce((propChangeInfo: IPublicTypePropChangeOptions) => { - const { - key, - newValue = null, - } = propChangeInfo; + const { key, newValue = null } = propChangeInfo; const node = leaf; if (key === '___condition___') { @@ -439,21 +453,36 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { this.beforeRender(RerenderType.PropsChanged); const { state } = this; const { nodeCacheProps } = state; - const nodeProps = getProps(node?.export?.(IPublicEnumTransformStage.Render) as IPublicTypeNodeSchema, scope, Comp, componentInfo); - if (key && !(key in nodeProps) && (key in this.props)) { + const nodeProps = getProps( + node?.export?.(IPublicEnumTransformStage.Render) as IPublicTypeNodeSchema, + scope, + Comp, + componentInfo, + ); + if (key && !(key in nodeProps) && key in this.props) { // 当 key 在 this.props 中时,且不存在在计算值中,需要用 newValue 覆盖掉 this.props 的取值 nodeCacheProps[key] = newValue; } - __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange!`, nodeProps, nodeCacheProps, key, newValue); - this.setState('children' in nodeProps ? { - nodeChildren: nodeProps.children, - nodeProps, - childrenInState: true, - nodeCacheProps, - } : { + __debug( + `${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange!`, nodeProps, nodeCacheProps, - }); + key, + newValue, + ); + this.setState( + 'children' in nodeProps + ? { + nodeChildren: nodeProps.children, + nodeProps, + childrenInState: true, + nodeCacheProps, + } + : { + nodeProps, + nodeCacheProps, + }, + ); this.judgeMiniUnitRender(); }); @@ -479,7 +508,9 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { return; } - __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange(${flag}) event`); + __debug( + `${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange(${flag}) event`, + ); this.beforeRender(RerenderType.VisibleChanged); this.setState({ visible: flag, @@ -498,16 +529,20 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { if (!this.autoRepaintNode) { return; } - const { - type, - node, - } = param || {}; + const { type, node } = param || {}; this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node); // TODO: 缓存同级其他元素的 children。 // 缓存二级 children Next 查询筛选组件有问题 // 缓存一级 children Next Tab 组件有问题 - const nextChild = getChildren(leaf?.export?.(IPublicEnumTransformStage.Render) as types.ISchema, scope, Comp); - __debug(`${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`, nextChild); + const nextChild = getChildren( + leaf?.export?.(IPublicEnumTransformStage.Render) as types.ISchema, + scope, + Comp, + ); + __debug( + `${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`, + nextChild, + ); this.setState({ nodeChildren: nextChild, childrenInState: true, @@ -518,7 +553,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } componentWillUnmount() { - this.disposeFunctions.forEach(fn => fn()); + this.disposeFunctions.forEach((fn) => fn()); } get hasChildren(): boolean { @@ -556,10 +591,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { return null; } - const { - forwardedRef, - ...rest - } = this.props; + const { forwardedRef, ...rest } = this.props; const compProps = { ...rest, @@ -597,4 +629,4 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { }); return LeafWrapper; -} \ No newline at end of file +} diff --git a/packages/renderer-core/src/renderer/page.tsx b/packages/renderer-core/src/renderer/page.tsx index 16d55e01b..d83dd200a 100644 --- a/packages/renderer-core/src/renderer/page.tsx +++ b/packages/renderer-core/src/renderer/page.tsx @@ -37,8 +37,30 @@ export default function pageRendererFactory(): IBaseRenderComponent { super.setState(state, callback); } + mergeStyle(schema: any) { + if (!schema || !Object.keys(schema).length) { + return; + } + + let style = schema.props.style ?? {}; + const { dynamicStyle } = schema.props; + + if (typeof dynamicStyle === 'object') { + console.log('dynamic: ', this.__parseData(dynamicStyle)); + style = { ...style, ...this.__parseData(dynamicStyle) }; + } + if (style && Object.keys(style).length) schema.props.style = style; + + if (!schema?.children) return; + + for (const child of schema.children) { + this.mergeStyle(child); + } + } + render() { const { __schema, __components } = this.props; + this.mergeStyle(__schema); if (this.__checkSchema(__schema)) { return '页面schema结构异常!'; }