LitElement:在小型 Web 组件中创建许多自定义样式规则与几个动态规则时的最佳实践(或最佳性能)?
LitElement: best practise (or best performance) when creating many custom style rules vs a couple of dynamic rules inside a tiny web component?
所以我正在开发一个非常小的 Web 组件,以作为更大的设计系统的一部分。
我对网络组件的使用有点陌生,但我知道这个特定的网络组件可以在一个布局中使用很多很多次。
此 Web 组件控制在传递给它的任何子组件周围放置多少垂直 space。
组件的剖析非常简单:
import { LitElement, html, css, unsafeCSS, property, customElement } from 'lit-element';
export const spacingAmounts = {
'x-small': css`4px`,
'small': css`8px`,
'medium': css`12px`,
'large': css`16px`,
'x-large': css`20px`,
'2x-large': css`30px`,
'3x-large': css`40px`,
'4x-large': css`60px`,
'5x-large': css`90px`,
'6x-large': css`120px`,
};
const createSpacingStyleRules = (direction: 'top' | 'bottom') => {
return Object.keys(spacingAmounts).map(s => {
const amount = spacingAmounts[s];
return css`
:host([${unsafeCSS(direction)}="${unsafeCSS(s)}"]) {
margin-${unsafeCSS(direction)}: ${unsafeCSS(amount)};
}
`;
});
};
@customElement('gu-vertical-space')
export class GuVerticalSpace extends LitElement {
@property() top: string;
@property() bottom: string;
static get styles() {
const styles = [
css`
:host {
display: block;
}
`,
// ----------------------------------------------------------
// @TODO:
// test if it's better performance wise to either:
//
// 1 - generate a verbose list of static styles for
// each instance of gu-vertical-space
// or
// 2 - generate a tiny amount of styles on the fly,
// based on property inputs...
// ----------------------------------------------------------
// ...createSpacingStyleRules('top'),
// ...createSpacingStyleRules('bottom'),
];
return styles;
}
render() {
const styles = [];
if (this.top) {
styles.push(css`
:host([top="${unsafeCSS(this.top)}"]) {
margin-top: ${spacingAmounts[this.top]}
}
`);
}
if (this.bottom) {
styles.push(css`
:host([bottom="${unsafeCSS(this.bottom)}"]) {
margin-bottom: ${spacingAmounts[this.bottom]}
}
`);
}
return html`
<style>${styles}</style>
<slot></slot>
`;
}
}
这里有 2 种方法可以将预定义的边距量映射到 Web 组件主机的顶部或底部。
当前有效的方法只是在渲染函数中动态生成一个 <style>
块,其中包含由 "top" 或 "bottom" 输入属性决定的任何边距量。
我正在考虑的另一种方法(尽管在 atm 中被注释掉了)是静态生成大量样式规则列表,从而避免在 render() 函数中生成任何动态样式内容的需要,这可能是一种反模式 - 如果我正确理解 lit-element docs 。
也许我缺少一种更优雅的方法?我倾向于当前的方法,只是因为它感觉更容易理解 - 但很好奇其他人的想法!
正如 Alan 所建议的,解决这个问题的一个更简单的方法是使用 css-变量。
基本上,只需将输入保证金量映射为 connect() 生命周期事件中的 css 变量(或者渲染,如果您认为道具在初始渲染后会发生变化)- 并调用这是一天!
static get styles() {
return css`
:host {
display: block;
margin-top: var(--margin-top);
margin-bottom: var(--margin-bottom);
}
`;
}
connectedCallback() {
super.connectedCallback();
this.style.setProperty(
'--margin-top',
this.top
? spacingAmounts[this.top]
: 'unset'
);
this.style.setProperty(
'--margin-bottom',
this.bottom
? spacingAmounts[this.bottom]
: 'unset'
);
}
所以我正在开发一个非常小的 Web 组件,以作为更大的设计系统的一部分。
我对网络组件的使用有点陌生,但我知道这个特定的网络组件可以在一个布局中使用很多很多次。
此 Web 组件控制在传递给它的任何子组件周围放置多少垂直 space。
组件的剖析非常简单:
import { LitElement, html, css, unsafeCSS, property, customElement } from 'lit-element';
export const spacingAmounts = {
'x-small': css`4px`,
'small': css`8px`,
'medium': css`12px`,
'large': css`16px`,
'x-large': css`20px`,
'2x-large': css`30px`,
'3x-large': css`40px`,
'4x-large': css`60px`,
'5x-large': css`90px`,
'6x-large': css`120px`,
};
const createSpacingStyleRules = (direction: 'top' | 'bottom') => {
return Object.keys(spacingAmounts).map(s => {
const amount = spacingAmounts[s];
return css`
:host([${unsafeCSS(direction)}="${unsafeCSS(s)}"]) {
margin-${unsafeCSS(direction)}: ${unsafeCSS(amount)};
}
`;
});
};
@customElement('gu-vertical-space')
export class GuVerticalSpace extends LitElement {
@property() top: string;
@property() bottom: string;
static get styles() {
const styles = [
css`
:host {
display: block;
}
`,
// ----------------------------------------------------------
// @TODO:
// test if it's better performance wise to either:
//
// 1 - generate a verbose list of static styles for
// each instance of gu-vertical-space
// or
// 2 - generate a tiny amount of styles on the fly,
// based on property inputs...
// ----------------------------------------------------------
// ...createSpacingStyleRules('top'),
// ...createSpacingStyleRules('bottom'),
];
return styles;
}
render() {
const styles = [];
if (this.top) {
styles.push(css`
:host([top="${unsafeCSS(this.top)}"]) {
margin-top: ${spacingAmounts[this.top]}
}
`);
}
if (this.bottom) {
styles.push(css`
:host([bottom="${unsafeCSS(this.bottom)}"]) {
margin-bottom: ${spacingAmounts[this.bottom]}
}
`);
}
return html`
<style>${styles}</style>
<slot></slot>
`;
}
}
这里有 2 种方法可以将预定义的边距量映射到 Web 组件主机的顶部或底部。
当前有效的方法只是在渲染函数中动态生成一个 <style>
块,其中包含由 "top" 或 "bottom" 输入属性决定的任何边距量。
我正在考虑的另一种方法(尽管在 atm 中被注释掉了)是静态生成大量样式规则列表,从而避免在 render() 函数中生成任何动态样式内容的需要,这可能是一种反模式 - 如果我正确理解 lit-element docs 。
也许我缺少一种更优雅的方法?我倾向于当前的方法,只是因为它感觉更容易理解 - 但很好奇其他人的想法!
正如 Alan 所建议的,解决这个问题的一个更简单的方法是使用 css-变量。
基本上,只需将输入保证金量映射为 connect() 生命周期事件中的 css 变量(或者渲染,如果您认为道具在初始渲染后会发生变化)- 并调用这是一天!
static get styles() {
return css`
:host {
display: block;
margin-top: var(--margin-top);
margin-bottom: var(--margin-bottom);
}
`;
}
connectedCallback() {
super.connectedCallback();
this.style.setProperty(
'--margin-top',
this.top
? spacingAmounts[this.top]
: 'unset'
);
this.style.setProperty(
'--margin-bottom',
this.bottom
? spacingAmounts[this.bottom]
: 'unset'
);
}