Created
May 16, 2024 05:22
-
-
Save audinue/2e48ae6f86f14b61b5cd8a5e7b707007 to your computer and use it in GitHub Desktop.
Immediate mode DOM diffing (a.k.a. incremental DOM). Applicable to native platforms (WinForms, Android)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { patch, begin, end, text } from "./immediate.js"; | |
var count = 0; | |
function tick(event) { | |
if (event.type === "click") { | |
if (event.target.id === "increment") { | |
count++; | |
} else if (event.target.id === "decrement") { | |
count--; | |
} | |
} | |
patch(document.body, function () { | |
begin("p"); | |
{ | |
text("Count: "); | |
text(count); | |
} | |
end(); | |
begin("p"); | |
{ | |
begin("button", { id: "increment" }); | |
{ | |
text("Increment"); | |
} | |
end(); | |
begin("button", { id: "decrement" }); | |
{ | |
text("Decrement"); | |
} | |
end(); | |
} | |
end(); | |
begin("ul"); | |
for (var i = 0; i < count; i++) { | |
begin("li"); | |
{ | |
text("Item "); | |
text(i); | |
} | |
end(); | |
} | |
end(); | |
}); | |
} | |
addEventListener("DOMContentLoaded", tick); | |
addEventListener("click", tick); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var parent; | |
var stack; | |
export function patch(container, render) { | |
parent = container; | |
stack = [container.firstChild]; | |
render(); | |
clearRemainder(); | |
} | |
export function begin(tag, attrs) { | |
patchTag(tag, attrs); | |
parent = getCurr(); | |
stack.push(parent.firstChild); | |
} | |
export function end() { | |
clearRemainder(); | |
parent = parent.parentNode; | |
stack.pop(); | |
moveNext(); | |
} | |
export function text(value) { | |
var curr = getCurr(); | |
if (!curr) { | |
var node = document.createTextNode(value); | |
parent.appendChild(node); | |
setCurr(node); | |
} else if (curr.nodeType !== 3) { | |
var node = document.createTextNode(value); | |
parent.replaceChild(node, curr); | |
setCurr(node); | |
} else if (curr.data !== String(value)) { | |
curr.data = String(value); | |
} | |
moveNext(); | |
} | |
export function tag(tag, attrs) { | |
patchTag(tag, attrs); | |
moveNext(); | |
} | |
function getCurr() { | |
return stack[stack.length - 1]; | |
} | |
function setCurr(curr) { | |
stack[stack.length - 1] = curr; | |
} | |
function moveNext() { | |
stack[stack.length - 1] = getCurr().nextSibling; | |
} | |
function createElement(tag, attrs) { | |
var el = document.createElement(tag); | |
for (var name in attrs) { | |
el.setAttribute(name, attrs[name]); | |
} | |
return el; | |
} | |
function clearRemainder() { | |
var curr = getCurr(); | |
while (curr) { | |
var next = curr.nextSibling; | |
parent.removeChild(curr); | |
curr = next; | |
} | |
} | |
function patchTag(tag, attrs) { | |
var curr = getCurr(); | |
if (!curr) { | |
var el = createElement(tag, attrs); | |
parent.appendChild(el); | |
setCurr(el); | |
} else if (curr.localName !== tag) { | |
var el = createElement(tag, attrs); | |
parent.replaceChild(el, getCurr()); | |
setCurr(el); | |
} else { | |
for (var name in attrs) { | |
var value = String(attrs[name]); | |
if (curr.getAttribute(name) !== value) { | |
curr.setAttribute(name, value); | |
} | |
} | |
for (var i = curr.attributes.length - 1; i > -1; i--) { | |
var name = curr.attributes[i].name; | |
if (!(name in attrs)) { | |
curr.removeAttribute(name); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment