tangled
alpha
login
or
join now
yippee.fun
/
morphlex
0
fork
atom
Precise DOM morphing
morphing
typescript
dom
0
fork
atom
overview
issues
pulls
pipelines
Performance improvements
joel.drapper.me
4 months ago
e7c28889
6c764bfd
+28
-9
1 changed file
expand all
collapse all
unified
split
src
morphlex.ts
+28
-9
src/morphlex.ts
···
129
129
}
130
130
131
131
private morphOneToOne(from: ChildNode, to: ChildNode): void {
132
132
+
// Fast path: if nodes are exactly the same object, skip morphing
133
133
+
if (from.isSameNode?.(to)) return
134
134
+
132
135
if (!(this.options.beforeNodeMorphed?.(from, to) ?? true)) return
133
136
134
137
const pair: PairOfNodes<ChildNode> = [from, to]
···
167
170
}
168
171
169
172
private morphAttributes([from, to]: PairOfMatchingElements<Element>): void {
170
170
-
// Remove any excess attributes from the element that aren’t present in the reference.
171
171
-
for (const { name, value } of from.attributes) {
172
172
-
if (!to.hasAttribute(name) && (this.options.beforeAttributeUpdated?.(from, name, null) ?? true)) {
173
173
-
from.removeAttribute(name)
174
174
-
this.options.afterAttributeUpdated?.(from, name, value)
175
175
-
}
176
176
-
}
173
173
+
const toAttrs = to.attributes
174
174
+
const fromAttrs = from.attributes
177
175
178
178
-
// Copy attributes from the reference to the element, if they don’t already match.
179
179
-
for (const { name, value } of to.attributes) {
176
176
+
// First pass: update/add attributes from reference (iterate forwards)
177
177
+
for (let i = 0; i < toAttrs.length; i++) {
178
178
+
const attr = toAttrs[i]!
179
179
+
const name = attr.name
180
180
+
const value = attr.value
180
181
const oldValue = from.getAttribute(name)
182
182
+
181
183
if (oldValue !== value && (this.options.beforeAttributeUpdated?.(from, name, value) ?? true)) {
182
184
from.setAttribute(name, value)
183
185
this.options.afterAttributeUpdated?.(from, name, oldValue)
186
186
+
}
187
187
+
}
188
188
+
189
189
+
// Second pass: remove excess attributes (iterate backwards for efficiency)
190
190
+
for (let i = fromAttrs.length - 1; i >= 0; i--) {
191
191
+
const attr = fromAttrs[i]!
192
192
+
const name = attr.name
193
193
+
const value = attr.value
194
194
+
195
195
+
if (!to.hasAttribute(name) && (this.options.beforeAttributeUpdated?.(from, name, null) ?? true)) {
196
196
+
from.removeAttribute(name)
197
197
+
this.options.afterAttributeUpdated?.(from, name, value)
184
198
}
185
199
}
186
200
}
···
264
278
const toChildNode = toChildNodes[i]!
265
279
266
280
if (fromChildNode) {
281
281
+
// Fast path: if nodes are exactly the same, skip morphing
282
282
+
if (fromChildNode.isSameNode?.(toChildNode)) {
283
283
+
continue
284
284
+
}
285
285
+
267
286
if (isElement(toChildNode)) {
268
287
this.searchSiblingsToMorphChildElement(fromChildNode, toChildNode, from)
269
288
} else {