@Speakermen

Каким образом синхронизируется реальное с виртуальным деревом DOM?

Каким образом они синхронизируются понять не могу(

637ce96bb4236082829243.jpeg

Нашёл тоже интересный код с обходом реального и построением виртуального или просто обходом реального
С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:Елисеев Дмитрий
  • Вопрос задан
  • 51 просмотр
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы