Vue 在浏览器是怎么跑起来的

143 阅读1分钟

首次渲染

createApp 就是项目的初始化渲染入口

export const createApp = ((...args) => {
  const app = ensureRenderer().createApp(...args)
  const { mount } = app
  // 重写mount
  app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
    const container = normalizeContainer(containerOrSelector)
    if (!container) return

    const component = app._component
    if (!isFunction(component) && !component.render && !component.template) {
      component.template = container.innerHTML
    }
    container.innerHTML = ''
    const proxy = mount(container, false, container instanceof SVGElement)
    if (container instanceof Element) {
      container.removeAttribute('v-cloak')
      container.setAttribute('data-v-app', '')
    }
    return proxy
  }
  return app
}) 
function normalizeContainer(container){
  if (isString(container)) {
    const res = document.querySelector(container)
  }
  return container
}

// 浏览器dom操作
import { nodeOps } from './nodeOps'
// 浏览器dom属性更新
import { patchProp } from './patchProp'
import { createRenderer } from '@vue/runtime-core'
const rendererOptions = extend({ patchProp }, nodeOps)

let renderer: Renderer<Element | ShadowRoot> | HydrationRenderer

function ensureRenderer() {
  return (
    renderer ||
    (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
  )
}  

通过createRenderer函数, 创建一个浏览器的渲染器, 缓存的渲染器的render, 传递的参数是nodeOps和patchProp 的合并对象

通过createApp 创建应用, 并且执行返回的mount方法实现在浏览器中的挂载, 在 createApp中通过传递浏览器平台的操作方法nodeOps 创建浏览器的 渲染器render

首次执行Vue 项目的时候, 通过patch 实现组件的渲染, patch 函数内部根据节点的不同类型, 去分别执行 processElement, processComponent, processText等方法去递归处理不同类型的几点, 最终通过setupComponent执行组件的setup函数, setupRenderEffect 中使用响应式的effect 函数监听数据的变化