refactor(perf): 优化插入 style 节点的逻辑, 避免无意义的删除和插入

This commit is contained in:
力皓 2021-04-21 09:44:52 +08:00
parent 4157aa0443
commit bedd598fc7
4 changed files with 41 additions and 20 deletions

View File

@ -291,6 +291,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
this._iframe = iframe; this._iframe = iframe;
this._contentWindow = iframe.contentWindow!; this._contentWindow = iframe.contentWindow!;
this._contentDocument = this._contentWindow.document;
const library = this.get('library') as LibraryItem[]; const library = this.get('library') as LibraryItem[];
const libraryAsset: AssetList = this.buildLibrary(); const libraryAsset: AssetList = this.buildLibrary();
@ -337,7 +338,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
renderer.run(); renderer.run();
// init events, overlays // init events, overlays
this._contentDocument = this._contentWindow.document;
this.viewport.setScrollTarget(this._contentWindow); this.viewport.setScrollTarget(this._contentWindow);
this.setupEvents(); this.setupEvents();

View File

@ -59,7 +59,7 @@ export default function (metadata: TransformedComponentMetadata): TransformedCom
}, },
{ {
description: '更新时', description: '更新时',
name: 'componentDidMount', name: 'componentDidUpdate',
}, },
{ {
description: '卸载时', description: '卸载时',

View File

@ -463,7 +463,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
container.id = containerId; container.id = containerId;
} }
// ==== compatiable vision // ==== compatible vision
document.documentElement.classList.add('engine-page'); document.documentElement.classList.add('engine-page');
document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends

View File

@ -2,24 +2,28 @@ import { editor, designer } from '@ali/lowcode-engine';
import { toCss } from '@ali/vu-css-style'; import { toCss } from '@ali/vu-css-style';
export function stylePropsReducer(props: any, node: any) { export function stylePropsReducer(props: any, node: any) {
let cssId;
let cssClass;
let styleProp;
if (props && typeof props === 'object' && props.__style__) { if (props && typeof props === 'object' && props.__style__) {
const cssId = `_style_pesudo_${ node.id.replace(/\$/g, '_')}`; cssId = `_style_pesudo_${node.id.replace(/\$/g, '_')}`;
const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`; cssClass = `_css_pesudo_${node.id.replace(/\$/g, '_')}`;
const styleProp = props.__style__; styleProp = props.__style__;
appendStyleNode(props, styleProp, cssClass, cssId); appendStyleNode(props, styleProp, cssClass, cssId);
} }
if (props && typeof props === 'object' && props.pageStyle) { if (props && typeof props === 'object' && props.pageStyle) {
const cssId = '_style_pesudo_engine-document'; cssId = '_style_pesudo_engine-document';
const cssClass = 'engine-document'; cssClass = 'engine-document';
const styleProp = props.pageStyle; styleProp = props.pageStyle;
appendStyleNode(props, styleProp, cssClass, cssId); appendStyleNode(props, styleProp, cssClass, cssId);
} }
if (props && typeof props === 'object' && props.containerStyle) { if (props && typeof props === 'object' && props.containerStyle) {
const cssId = `_style_pesudo_${ node.id}`; cssId = `_style_pesudo_${node.id}`;
const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`; cssClass = `_css_pesudo_${node.id.replace(/\$/g, '_')}`;
const styleProp = props.containerStyle; styleProp = props.containerStyle;
appendStyleNode(props, styleProp, cssClass, cssId); appendStyleNode(props, styleProp, cssClass, cssId);
} }
props.className = cssClass;
return props; return props;
} }
@ -28,21 +32,38 @@ function appendStyleNode(props: any, styleProp: any, cssClass: string, cssId: st
if (!doc) { if (!doc) {
return; return;
} }
const dom = doc.getElementById(cssId); const dom = doc.getElementById(cssId) as HTMLStyleElement;
if (dom) {
dom.parentNode?.removeChild(dom);
}
if (typeof styleProp === 'object') { if (typeof styleProp === 'object') {
styleProp = toCss(styleProp); styleProp = toCss(styleProp);
} }
if (typeof styleProp === 'string') { if (typeof styleProp === 'string') {
const newStyleStr = transformStyleStr(styleProp, cssClass);
if (dom && stringEquals(dom.textContent!, newStyleStr)) {
return;
}
if (dom) {
dom.parentNode?.removeChild(dom);
}
const s = doc.createElement('style'); const s = doc.createElement('style');
props.className = cssClass;
s.setAttribute('type', 'text/css'); s.setAttribute('type', 'text/css');
s.setAttribute('id', cssId); s.setAttribute('id', cssId);
doc.getElementsByTagName('head')[0].appendChild(s); doc.getElementsByTagName('head')[0].appendChild(s);
s.appendChild(doc.createTextNode(styleProp.replace(/(\d+)rpx/g, (a, b) => { s.appendChild(doc.createTextNode(newStyleStr));
return `${b / 2}px`;
}).replace(/:root/g, `.${cssClass}`)));
} }
} }
function stringEquals(str: string, targetStr: string): boolean {
return removeWhitespace(str) === removeWhitespace(targetStr);
}
function removeWhitespace(str: string = ''): string {
return str.replace(/\s/g, '');
}
function transformStyleStr(styleStr: string = '', cssClass: string): string {
return styleStr
.replace(/(\d+)rpx/g, (all, num) => {
return `${num / 2}px`;
})
.replace(/:root/g, `.${cssClass}`);
}