首次渲染
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 函数监听数据的变化