vue2源码简单实现stage1

其实看了很多的vue源码,很多的东西只是脑子会了,能说就是写不出来。vue的源码有很多的边界判断的代码,纯粹的核心原理代码其实并不多,刚好看到一个比较好的vue2源码精简版,自己手动跟着敲一敲,作为记录,希望自己对源码的理解更深一点。Talk is cheap,Show me the code,让我们愉快的开始实现vue2核心代码吧。这一节我们先实现一下如何让虚拟dom转变为真是的dom

mouted主要干了什么?

// vue-0.1.js
const app = new Vue({
    render: h => h(App)
});
app.$mount('#app');

我们可以理解挂在的时候就是生成虚拟dom并其转为真实的dom,让后替换掉我们指定的div元素。

;(function(){
  function mount(el){
    // 生成vdom
    var vnode = render();
    //转成真实dom并且替换原来的指定的dom
    patch(el, vnode)
  }
})()

初始虚拟dom

用普通js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。虚拟 dom 是相对于浏览器所渲染出来的真实dom而言的

// vue-0.1.js
{
    tag: 'div',// 表述标签,如p、sapn
    data: {
        attrs: {
          'class': 'wrapper'
        }
    },
    children: [
      tag: "p",
      data:{
        attrs: {
           'class': 'inner'
         }
      },
      children:[
        text:'Hello world'
      ]
      text:''
    ],
    text: 'virtual dom', //标签内的文本,
}

// 构造render函数,生成virtual dom,这里为了让代码更加简洁,这里就先直接忽略template模板的的循环结构部分,直接将描述模板写到render里面,生成虚拟dom

// vue-0.1.js
;(function(){
  
  function vnode (tag, data, children, text) {
    this.tag = tag;
    this.data = data;
    this.children = children;
    this.text = text;
  }
  function render () {
    return new vnode(
      'div',
      {
        attrs: {
          'class': 'wrapper'
        }
      },
      [
        new vnode(
          'p',
          { 
            attrs: {
              'class': 'inner'
            }
          },
          [new vnode(undefined, undefined, undefined, 'Hello world')]
        )
      ],
      'virtual dom'
    )
  }
  function mount(el){
    // 生成vdom
    var vnode = render();
    //转成真实dom并且挂载在根元素上
    patch(el, vnode)
  }
})()

打印上面的vnode

// 通过上面的方法我们已经得到了一个描述以下真实dom的虚拟dom了

  <div class= 'wrapper'>
    <p class= 'inner'>
      'Hello world'
    </p>
    'virtual dom'
   </div>

下面我们要通过createElm将虚拟dom转变为真实的dom元素

// vue-0.1.js
;(function(){
  function createElm (vnode) {
    var tag = vnode.tag;
    var data = vnode.data;
    var children = vnode.children;
    var text = vnode.text
    //生成对应的标签
    if (tag !== undefined) {
      
      vnode.elm = document.createElement(tag);
      //循环vnode下面的属性
      if (data.attrs !== undefined) {
        var attrs = data.attrs;
        for (var key in attrs) {
          vnode.elm.setAttribute(key, attrs[key])
          vnode.elm.innerHTML = text!==undefined? text:''
        }
      }
      if (children) {
        createChildren(vnode, children)
      }
    } else {
      vnode.elm = document.createTextNode(vnode.text);
    }

    return vnode.elm;
  }

  function createChildren (vnode, children) {
    for (var i = 0; i < children.length; ++i) {
      vnode.elm.appendChild(createElm(children[i]));
    }
  }
  function patch (oldVnode, vnode) {
    createElm(vnode)
    // virtual node has no `nodeType` property
    var isRealElement = oldVnode.nodeType !== undefined ; 
    //这一判断逻辑也给出了vue的绑定的元素不能是body和document元素
    if (isRealElement) {
      var parent = oldVnode.parentNode;
      if (parent) {
        parent.insertBefore(vnode.elm, oldVnode);
        parent.removeChild(oldVnode);
      }
    }
    return vnode.elm
  }
  function vnode (tag, data, children, text) {
    this.tag = tag;
    this.data = data;
    this.children = children;
    this.text = text;
  }
  function render () {
    return new vnode(
      'div',
      {
        attrs: {
          'class': 'wrapper'
        }
      },
      [
        new vnode(
          'p',
          { 
            attrs: {
              'class': 'inner'
            }
          },
          [new vnode(undefined, undefined, undefined, 'Hello world')]
        )
      ],
      'virtual dom'
    )
  }
  function mount(el){
    // 生成vdom
    var vnode = render();
    //转成真实dom并且挂载在根元素上
    patch(el, vnode)
  }
})()
posted @ 2021-12-14 15:59  自在一方  阅读(90)  评论(0编辑  收藏  举报