- From: James Browning <notifications@github.com>
- Date: Sun, 24 Mar 2019 18:30:45 -0700
- To: w3c/webcomponents <webcomponents@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <w3c/webcomponents/issues/704/476025026@github.com>
@dmitriid Neither template instantiation or `lit-html` use `.innerHTML` to update the DOM. This seems to be some FUD around how template instantiation works but template instantiation and `lit-html` actually work *more* efficiently than a virtual DOM by holding references to part of the DOM that have template parts. In `lit-html`'s case, it *only* creates the initial template using `.innerHTML`, to actually update the DOM it [inserts nodes directly into the correct location (and similar for attributes)](https://github.com/Polymer/lit-html/blob/master/src/lib/parts.ts#L203).
For example consider this template:
```html
<template id="exampleTemplate">
<span title="{{foo}}">This is a sample {{bar}} with instantiation</span>
<span>Also {{foo}}</span>
</template>
```
when we create an instance of the template a set of references are created to the elements that have that name:
```
{
foo: [
AttributeTemplatePart {
el: /* ref to <span title="{{foo}}"> element */
attrName: 'title',
},
NodeTemplatePart {
previousNode: /* The previous text node before {{foo}}: "Also" */
nextNode: /* The text node after {{foo}} */
},
],
bar: [
NodeTemplatePart {
previousNode: /* The previous text node before {{bar}}: "This is a sample " */
nextNode: /* The next text node after {{bar}}: " with instantiation"
}
],
}
```
now when we call something like `instance.update({ foo: 'banana', bar: 'cabbage' })` all `.update` needs to do is something like this:
```js
function update(data) {
for (const [key, value] of Object.entries(data)) {
for (const templatePart of this._templateParts[key]) {
templatePart.update(value)
}
this._templateParts[key].update(value)
}
}
```
this is *way more efficient* than maintaining a virtual copy of the DOM as we simply implement `AttributeTemplatePart` and `NodeTemplatePart` so that they go directly to their location in the DOM and update the value.
e.g. `NodeTemplatePart` could be implemented like this:
```js
class NodeTemplatePart {
constructor(previousNode, nextNode) {
this._previousNode = previousNode
this._nextNode = nextNode
}
// This is overly simplified and assumes there's a node both before and after
// the {{curlies}}, a real implementation would hold a reference to the parent element
// as well and if there's no previousNode/nextNode it'd just replace the whole contents
update(values) {
if (typeof values === 'string') {
values = [new Text(values)]
}
while (this._previousNode.nextNode !== this._nextNode) {
this._previousNode.nextNode.remove()
}
for (const value of values) {
this._nextNode.parentNode.insertBefore(value, this._nextNode)
}
}
}
```
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/704#issuecomment-476025026
Received on Monday, 25 March 2019 01:31:07 UTC