template 与 render()
这一心智模型旨在降低编写组件时的认知复杂度:
template是一个只读属性(用get关键字初始化),表示组件视图如何被渲染。- 有一个
render()方法会触发视图渲染。 - 每当属性值发生变化,这个
render()方法就会在底层自动被调用。 - 如果需要,你可以在任意时刻可选地调用这个
render()方法来触发渲染(例如,当你有私有的、未被观察的属性需要手动触发渲染时) - 也可以重写
render()函数来处理自定义template。这里有一个使用lit-html的示例:在 CodePen 上查看 ↗
查看实况:模板化演示 ↗ 展示了两种模板类型,渲染协调演示 ↗ 展示了原地重新渲染能保留哪些内容:焦点、光标位置和尚未提交的输入值都会被保留。
一个组件的 template 可以包含其他组件,并可以嵌套至任意深度:
class CounterBoard extends WebComponent { static props = { title: 'Board' } get template() { return html` <h3>${this.props.title}</h3> <counter-row name="alpha"></counter-row> <counter-row name="bravo"></counter-row> ` }}每个嵌套组件都自行拥有它所渲染的 DOM。当外层组件重新渲染时, 协调器会 patch 它传递给嵌套元素的 props(这正是数据从父到子流动的方式), 但绝不会触碰该元素自身的子节点,因此即使祖先组件因无关原因重新渲染, 嵌套组件也会保留其已渲染的内容及任何内部状态。数据以属性形式向下流动, 因此传递的值应当是嵌套组件能够从属性中读回的:原始值,或是能经过 JSON 往返转换而保持不变的对象/数组。查看实况:嵌套组合演示 ↗。
唯一的例外是插槽投影(slot projection):你写在一个 shadow-DOM
组件标签内部的子元素属于你的内容,会被投影到它的 <slot> 中,因此
父组件会继续协调这些内容。相比之下,light-DOM 组件会渲染覆盖其自身的子节点,
因此应当通过属性而不是通过投影子元素向它传递数据。