vue3渲染器的黑魔法

186 阅读2分钟

哈喽大家好,我是西瓜,本人正在研究vue3的源码,在这里和大家分享一下。

前言

大家用vue3的时候有没有觉得相比js实在是太方便了,那么vue中的模板是怎么渲染下来的呢。

目标

深入理解vue渲染器的挂载流程

流程解读

vue是通过一个函数进行的渲染dom操作

这里给大家举个例子

function render (html, container) {
  document.querySelector(container).innerHTML = html
}

当然了,vue可不是只用这么简单就实现了渲染。

vue中render实际是调用一个名为patch的函数进行数据处理,下面我们来实现一下patch

function render (vnode, container) {
  patch(null, vnode, container)
}

patch会接收三个参数,

  1. n1 -> 之前的数据
  2. n2 -> 新的数据
  3. container -> 父级元素

patch判断n2是组件类型还是元素类型,如果为元素类型则执行processElement,如果为组件类型会执行processComponent函数。

function patch (n1, n2, container) {
  if (typeof n2.type === 'string') {
      processElement(n1, n2, container)
  } else {
      processComponent(n1, n2, container)
  }
}

我们先来实现一下vue挂载元素的流程

这里当n1为空时则表示是挂载操作,当n1存在为更新操作,更新操作相对复杂,后面单独出一篇文章讲解更新操作。

当n1不存在执行mountElement,也就是挂载操作

function processElement (n1, n2, container) {
  if (!n1) {
    mountElement(n2, container)
  }
}

mountElement是用来处理挂载数据的,这里我们来实现一下

function mountElement (vnode, container) {
  const { type, props, children } = vnode
  // type -> 元素类型 div/span等
  // props -> 元素的属性
  // children -> 子级元素
  const el = document.createElement(type)

  if (props) {
    // 因为在vue中我们会把开头为on的数据认为事件,所以只需要判断on来区分事件
    for (const key in props) {

      const val = props[key]

      if (/^on/.test(key)) {
        // 绑定事件
        const _event = key.slice(2).toLocaleLowerCase()
        el.addEventListener(_event, val)
      } else {
        // 如果属性没有则删除属性,如果有就进行添加操作
        if (val === null || val === undefined) {
          el.removeAttribute(key)
        } else {
          el.setAttribute(key, val)
        }
      }
    }
  }

  // 如果子级为多个的就遍历执行patch,否则就赋值
  if (Array.isArray(children)) {
    children.forEach((childNode) => {
      patch(null, childNode, el)
    })
  } else {
    el.textContent = children
  }

  // 添加到父级中
  container.append(el)
}

这样我们就实现了一个vue挂载元素的简单流程。

大家也可以查看我的github地址,github.com/Rafael-wxd

实现了一个简单的vue3

觉得可以的就欢迎点赞、收藏加关注吧。