问题:是否可以在不触发其render
函数的情况下将属性更改传播到子元素?当前,当我更新父级switchViewModeHandler
中的属性时,它会触发子级的重新渲染。
用例:将父级切换到“编辑”模式也应为其所有子级切换相同的状态。
疑问:我应该使用自定义事件吗?问题在于它将是一个由嵌套元素组成的复杂网络,事件一旦发生,它将很快变得难以调试(Polymer已经遇到了这个问题)。
设置:父元素:
class ParentElement extends LitElement {
@property() viewMode;
constructor() {
this.viewMode = ViewMode.editable;
}
static get properties() {
return {
viewMode: { type: String, reflect: true },
};
}
private switchViewModeHandler(event: MouseEvent): void {
this.viewMode =
(this.viewMode === ViewMode.editing) ? ViewMode.editable : ViewMode.editing; // update my own edit mode
const options: HTMLElement[] = (Array.from(this.children) as HTMLElement[]);
options.forEach((item: HTMLElement) => {
item.viewMode = this.viewMode;
});
}
render() {
return html`
<p>parent</p><label class="switch-wrapper">toggle edit mode
<input type="checkbox"
?checked="${this.viewMode === ViewMode.editing}"
@click="${
(event: MouseEvent): void => this.switchViewModeHandler(event)
}"
/>
</label>
<slot></slot><!-- child comes from here -->
`;
}
}
子元素:
class ChildElement extends LitElement {
@property() viewMode;
constructor() {
super();
this.viewMode = ViewMode.editable;
}
static get properties() {
return {
viewMode: { type: String, reflect: true },
};
}
render() {
console.log('child render() called');
return html`
<div class="viewer">child viewer</div>
<div class="editor mode-${this.viewMode}">child editor</div>
`;
}
}
标记:
<parent-element>
<child-element data-type="special"></child-element
></parent-element>
编辑模式来自导入的一个简单枚举(此处省略):
export enum ViewMode {
readOnly = 'readOnly',
editable = 'editable',
editing = 'editing',
}
这是一个可与以下代码一起使用的Codesandbox:https://codesandbox.io/s/v1988qmn75
答案 0 :(得分:3)
向轻量级DOM子代传播状态是一种相对很少需要的模式,因此我们尚未对其进行充分的记录,但是在某些情况下(如您的情况)有必要。
正确的方法实际上取决于容器元素的子元素如何受到控制。如果您(也是父元素的作者)也是唯一的用户,并且确切地知道了子元素的含义,那么您将拥有更大的灵活性。
我能想到的选项是:
<child prop=${x}></child>
语法一样。我想说,您在事件处理程序中设置子状态的方法并不遥远,除了它与用户交互事件而不是状态本身息息相关。
我会选择一些您总是在updated()
中更新状态的东西:
class ParentElement extends LitElement {
@property({ type: String, reflect: true })
viewMode = ViewMode.editable;
private _onSwitchClicked(event: MouseEvent): void {
this.viewMode = (this.viewMode === ViewMode.editing)
? ViewMode.editable
: ViewMode.editing;
}
private _onSlotChange() {
this.requestUpdate();
}
updated() {
for (const child of Array.from(this.children)) {
child.viewMode = this.viewMode;
}
}
render() {
return html`
<p>parent</p>
<label class="switch-wrapper">toggle edit mode
<input type="checkbox"
?checked=${this.viewMode === ViewMode.editing}
@click=${this._onSwitchClicked}>
</label>
<slot @slotchange=${this._onSlotChange}></slot>
`;
}
}
如果子元素是LitElement且值是基元,则始终可以设置属性-在子元素中对它们进行脏检查是可以的。
请注意slotchange
上的<slot>
事件处理程序,以便我们观察子级。