<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script>
// 这里就是自定义渲染器renderer的工具方法
const nodeOps = {
querySelector(selector){
return document.querySelector(selector)
},
createElement(tag){
return document.createElement(tag)
},
setElementText: (el, text) => {
el.textContent = text
},
insert(child,parent,anchor){
parent.insertBefore(child,anchor || null)
}
}
</script>
<script>
const VUE = {
createApp: (options) => {
// 实际调用
const renderer = ensureRenderer()
const app = renderer.createApp(options)
return app
}
}
const ensureRenderer = ()=>{
return createRrenderer(nodeOps)
}
const createRrenderer = (nodeOps) => {
return baseCreateRenderer(nodeOps)
}
const baseCreateRenderer = (nodeOps) => {
// 此处的patch为伪代码,只是进行了初始化dom插入操作,源码还做了更新节点(涉及新旧vnode对比)等功能
const patch = (oldVnode,newVnode,container)=>{
const options = newVnode.options
const data = options.setup()
// 这里源码应该为代理,此处省略直接将传递的 data给render传进去
const vnode = options.render.call(data)
// 获取容器dom
const parent = nodeOps.querySelector(container)
// 获取子节点
const child = nodeOps.createElement(vnode.tag)
// 设置子节点children内容(示例中内容为文本)
nodeOps.setElementText(child,vnode.children)
// 将子节点插入容器,进行dom挂载
nodeOps.insert(child,parent)
}
// 参数;虚拟dom、容器
const render = (vnode,container) => {
// 将虚拟dom转化为真实dom,然后插入到容器内
patch(container._vnode,vnode,container)
container._vnode = vnode
}
return {
createApp: createAppAPI(render)
}
}
const createAppAPI = (render)=>{
// options: 传递的data等选项
return function createApp(options) {
const app = {
mount(selector){
// 模拟创建vnode
const vnode = {
options
}
// 渲染
render(vnode,selector)
}
}
return app
}
}
</script>
<script>
const { createApp } = VUE
// 调用的实际是渲染器的createApp
const app = createApp({
setup() {
// 此示例没有响应式,所以未出现ref
const msg = 'hello! vue3'
return {msg}
},
// 此处的render为模拟vnode,源码vnode应该结合vue的compiler产生
render(){
return {
tag:'h2',
children:this.msg,
}
}
})
app.mount('#app')
</script>
</body>
</html>
如何理解vue3渲染器,手写模拟vue3初始化过程
于 2024-03-23 14:00:34 首次发布