Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Something About Virtual DOM

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

Something About Virtual DOM

implement virtual dom by yourself :)

Avatar for Jason Liao

Jason Liao

August 12, 2016

More Decks by Jason Liao

Other Decks in Technology

Transcript

  1. W3C 也意识到了这个问题,提出了 Shadow DOM 的标准,实际上 它也是用标准的 API 去把组合多个 DOM tree

    到一个 host 节点里 形成组件,使得 DOM tree 之间更好的交互,更好的组合 Shadow DOM ‒ Ediror's Draft Shadow DOM v1: self‒contained web components
  2. Virtual DOM 的思想在于,把 DOM tree 转成 JavaScript 的 Object,因为浏览器处理 JavaScript

    更快,而且更简单。 一个 Node 节点可以很容易的用 Object 来表示
  3. // <a href="https://github.com/jasonliao">Follow Me:)</a> const Follow = { tag: 'a',

    props: { href: 'https://github.com/jasonliao' }, children: ['Follow Me:)'] }; // <div class="intr"> // <p>Hi, my name's Jason</p> // <a href="https://github.com/jasonliao">Follow Me:)</a> // </div> const Intr = { tag: 'div', props: { className: 'intr' }, children: [{ tag: 'p', children: ['Hi, my name\'s Jason'] }, Follow] };
  4. Virtual DOM 的算法包括几个步骤 1. 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构 建一个真正的

    DOM 树,插到文档当中(toHTML) 2. 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和 旧的树进行比较,记录两棵树差异(diff) 3. 把 2 所记录的差异应用到步骤 1 所构建的真正的DOM树上, 视图就更新了(patch)
  5. toHTML(Element.js) 我们创建一个 Element 对象,传入 tagName 、 props 、 children 三

    个参数,再通过 toHTML 方法,把这个对象转成 HTML
  6. Diff(diff.js) Diff 是 Virtual DOM 最核心的部分,它的算法关乎整个运行的效 率,我不会高深的算法,但按照基本思路,我实现了一个自己的 Diff 首先定义一个差异对象 patches

    , patches 的 key 是树的节点, 用 0, 1, 2 表示,每个值则为一个数组,里面装着这个节点的差异。 归结起来有四种差异:
  7. 例如 // <p>Awesome</p> => <p class="wow">Fantastic</p> patches: { '0': [{

    type: 'PROPS', content: { className: 'wow' } }, { type: 'TEXT', content: 'Fantastic' }] }
  8. const HVVD = { tagName: 'div', children: [{ tagName: 'h1',

    children: ['Hello, ', { tagName: 's', children: ['Visual'] }, 'Virtual DOM'] }, { tagName: 'button', props: { id: 'btn' }, children: ['Tada!'] }] } const HVD = { tagName: 'div', children: [{ tagName: 'h1', children: ['Hello, Virtual DOM'] }] }
  9. 先把 HVVD 渲染在页面上,并为 button 绑定一个事件,点击按钮 时,把 HVVD 和 HVD 做

    Diff,得到 patches ,并用 patch 函数应 用到视图中 const root = document.querySelector('#root'), btn = document.querySelector('#btn'); root.appendChild(new Element(HVVD).toHTML()); btn.addEventListener('click', function() { const patches = diff(HVVD, HVD); console.log(patches); patch(root, patches); })
  10. 然后看下打印出来的 patches { "2": [{ type: "TEXT", content: "Hello, Virtual

    DOM" }], "3": [{ type: "REPLACE", node: undefined }], "5": [{ type: "REPLACE", node: undefined }], "6": [{ type: "REPLACE", node: undefined }], }