16节-render转vnode并挂载到页面上

77 阅读1分钟

入口文件

import { initMixin } from './init'
import { lifecycleMixin } from './lifecycle/index'
import { renderMixin } from './vdom/index'

function Vue(options) {
  // 初始化
  this.__init(options);
}

initMixin(Vue);//初始化

// ------- 这部分是本次的内容
lifecycleMixin(Vue);//产生生命周期
renderMixin(Vue);

export default Vue

生命周期挂在render方法 lifecycle/index.js

import { patch } from '../vdom/patch';

export function mountComponent(vm) {
  vm._update(vm._render());
}

export function lifecycleMixin(Vue) {
  Vue.prototype._update = function(vnode) {
    // console.log(vnode);
    const vm = this;
    patch(vm.$el, vnode);
  }
}

render转vnode vdom/index.js

import {
  createElement,
  createTextVnode
} from './vnode.js'  

export function renderMixin(Vue) {
  // 创建元素信息
  Vue.prototype._c = function() {
    return createElement(...arguments);
  }
  Vue.prototype._s = function(value) {
    if(value === null) return;
    return typeof value === 'object' ? JSON.stringify(value): value;
  }
  Vue.prototype._v = function(text) {
    return createTextVnode(text);
  }

  Vue.prototype._render = function() {
    const vm = this,
          render = vm.$options.render,
          vnode = render.call(vm);
    return vnode;
  }
}

实现功能文件 vdom/vnode.js

function createElement(tag, attrs = {}, ...children) {
  return vnode(tag, attrs, children);
}


function createTextVnode(text) {
  return vnode(undefined, undefined, undefined, text);
}

function vnode(tag, props, children, text) {
  return {
    tag, 
    props, 
    children, 
    text
  }
}

export {
  createElement,
  createTextVnode
}

打补丁挂载页面 vdom/patch.js

// 打补丁
function patch(oldNode, vnode) {
  let el = createElement(vnode),
      parentElement = oldNode.parentNode;
  parentElement.insertBefore(el, oldNode.nextSibling);
  parentElement.removeChild(oldNode);
}

function createElement(vnode) {
  const { tag, props, children, text } = vnode;


  if(typeof tag === 'string') {//是一个标签
    vnode.el = document.createElement(tag);
    // 处理属性
    updateProps(vnode, props);
    // 遍历children
    children.map(child => {
      vnode.el.appendChild(createElement(child));
    })
  }else {//文本节点
    vnode.el = document.createTextNode(text);
  }
  return vnode.el;
}

function updateProps(vnode) {
  console.log(vnode, 1111);
  const el = vnode.el,
        newProps = vnode.props || {};
  for(let key in newProps) {
    if(key === "style") {
      for(let skey in newProps.style) {
        el.style[skey] = newProps.style[skey];
      }
    }else if(key === 'class'){  
      el.className = el.class;
    }else {
      el.setAttribute(key, newProps[key]);
    }
  }
}

export {
  patch
}
  • 挂载之前: image.png
  • 打补丁挂载之后 image.png