Каким образом они синхронизируются понять не могу(
Нашёл тоже интересный код с обходом реального и построением виртуального или просто обходом реального
Сodepen DOM Tree Viewer
Упрощенный вариант мне понятен
function App({ state }) {
const app = document.createElement("div");
app.className = "app";
app.appendChild(Header());
app.appendChild(Clock({ time: state.time }));
app.appendChild(Lots({ lotsData: state.lotsData }));
return app;
}
function render(dom, virtuelDom) {
dom.innerHTML = "";
dom.append(virtuelDom);
}
function renderView({ state }) {
render(document.getElementById("root"), App({ state }));
}
Но этот фрагмент нет
function synchronizationChildNodes(realNode, virtualNode) {
const virtualNodeChildrens = virtualNode.childNodes;
const realNodeChildrens = realNode.childNodes;
for (
let i = 0;
i < virtualNodeChildrens.length || i < realNodeChildrens.length;
i++
) {
const virtualNodeChildren = virtualNodeChildrens[i];
const realNodeChildren = realNodeChildrens[i];
remove(virtualNodeChildren, realNodeChildren, realNode);
update(virtualNodeChildren, realNodeChildren);
replace(virtualNodeChildren, realNodeChildren, realNode);
add(virtualNodeChildren, realNodeChildren, realNode);
}
}
function add(virtualNodeChildren, realNodeChildren, realNode) {
if (virtualNodeChildren !== undefined && realNodeChildren === undefined) {
const updateRealNodeChildren = createRealNode(virtualNodeChildren);
synchronization(updateRealNodeChildren, virtualNodeChildren);
realNode.appendChild(updateRealNodeChildren);
}
}
function createRealNode(virtualChildren) {
if (virtualChildren.nodeType === Node.TEXT_NODE) {
return document.createTextNode("");
}
return document.createElement(virtualChildren.tagName);
}
Весь код
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
border: 0;
}
body {
font-family: Arial, sans-serif;
margin: 8px;
line-height: 1.2;
}
.app {
max-width: 500px;
}
.logo {
max-width: 100%;
}
.header {
margin-bottom: 10px;
height: 100px;
}
.header .logo {
display: block;
width: 96px;
height: 96px;
}
.clock {
padding: 15px;
border: 1px solid #ddd;
border-radius: 6px;
margin-bottom: 10px;
}
.lot {
padding: 15px;
border: 1px solid #ddd;
border-radius: 6px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div id="root"></div>
<script src="./dew10.js"></script>
</body>
</html>
Create element
let state = {
time: new Date(),
lotsData: [
{ id: 1, title: "Apple", description: "Apple description", price: "16" },
{ id: 2, title: "Orange", description: "Orange description", price: "41" },
],
};
function Logo() {
const logo = document.createElement("img");
logo.src = "img-logo.png";
logo.className = "logo";
logo.alt = "logo";
return logo;
}
function Header() {
const header = document.createElement("header");
header.className = "header";
header.appendChild(Logo());
return header;
}
function Clock({ time }) {
const clock = document.createElement("div");
clock.className = "clock";
clock.innerText = time.toLocaleTimeString();
return clock;
}
function Lot(lotData) {
const lot = document.createElement("article");
lot.className = "lot";
const price = document.createElement("div");
price.className = "price";
price.innerText = lotData.price;
lot.appendChild(price);
const h1 = document.createElement("h1");
h1.innerText = lotData.title;
lot.appendChild(h1);
const p = document.createElement("p");
p.innerText = lotData.description;
lot.appendChild(p);
return lot;
}
function Lots({ lotsData }) {
const lots = document.createElement("div");
lots.className = "lots";
lotsData.forEach((lotData) => {
lots.appendChild(Lot(lotData));
});
return lots;
}
function App({ state }) {
const app = document.createElement("div");
app.className = "app";
app.appendChild(Header());
app.appendChild(Clock({ time: state.time }));
app.appendChild(Lots({ lotsData: state.lotsData }));
return app;
}
render
function render(realDom, virtualDom) {
const virtualDomRoot = document.createElement(realDom.tagName);
virtualDomRoot.id = realDom.id;
virtualDomRoot.append(virtualDom);
synchronization(realDom, virtualDomRoot);
}
function renderView({ state }) {
render(document.getElementById("root"), App({ state }));
}
renderView({ state });
setInterval(() => {
state = {
...state,
time: new Date(),
};
renderView({ state });
});
Магия синхронизации
function synchronization(realNode, virtualNode) {
synchronizationElement(realNode, virtualNode);
synchronizationChildNodes(realNode, virtualNode);
}
function synchronizationElement(realNode, virtualNode) {
if (virtualNode.id !== realNode.id) {
realNode.id = virtualNode.id;
}
if (virtualNode.className !== realNode.className) {
realNode.className = virtualNode.className;
}
if (virtualNode.attributes) {
Array.from(virtualNode.attributes).forEach((attribute) => {
realNode[attribute.name] = attribute.value;
});
}
if (virtualNode.nodeValue !== realNode.nodeValue) {
realNode.nodeValue = virtualNode.nodeValue;
}
}
function synchronizationChildNodes(realNode, virtualNode) {
const virtualNodeChildrens = virtualNode.childNodes;
const realNodeChildrens = realNode.childNodes;
for (
let i = 0;
i < virtualNodeChildrens.length || i < realNodeChildrens.length;
i++
) {
const virtualNodeChildren = virtualNodeChildrens[i];
const realNodeChildren = realNodeChildrens[i];
remove(virtualNodeChildren, realNodeChildren, realNode);
update(virtualNodeChildren, realNodeChildren);
replace(virtualNodeChildren, realNodeChildren, realNode);
add(virtualNodeChildren, realNodeChildren, realNode);
}
}
function remove(virtualNodeChildren, realNodeChildren, realNode) {
if (virtualNodeChildren === undefined && realNodeChildren !== undefined) {
//const updateRealNodeChildren = createRealNode(virtualNodeChildren);
//synchronization(updateRealNodeChildren, virtualNodeChildren);
//realNode.appendChild(updateRealNodeChildren);
realNode.remove(realNodeChildren);
}
}
function add(virtualNodeChildren, realNodeChildren, realNode) {
if (virtualNodeChildren !== undefined && realNodeChildren === undefined) {
const updateRealNodeChildren = createRealNode(virtualNodeChildren);
synchronization(updateRealNodeChildren, virtualNodeChildren);
realNode.appendChild(updateRealNodeChildren);
}
}
function update(virtualNodeChildren, realNodeChildren) {
if (
virtualNodeChildren !== undefined &&
realNodeChildren !== undefined &&
virtualNodeChildren.tagName === realNodeChildren.tagName
) {
synchronization(realNodeChildren, virtualNodeChildren);
}
}
function replace(virtualNodeChildren, realNodeChildren, realNode) {
if (
virtualNodeChildren !== undefined &&
realNodeChildren !== undefined &&
virtualNodeChildren.tagName !== realNodeChildren.tagName
) {
const updateRealNodeChildren = createRealNode(virtualNodeChildren);
synchronization(updateRealNodeChildren, virtualNodeChildren);
realNode.replace(updateRealNodeChildren, realNodeChildren);
}
}
function createRealNode(virtualChildren) {
if (virtualChildren.nodeType === Node.TEXT_NODE) {
return document.createTextNode("");
}
return document.createElement(virtualChildren.tagName);
}
Авторы кода:
Ivan Bogachev
Что есть React:Елисеев Дмитрий