如何理解vue3渲染器,手写模拟vue3初始化过程

<!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>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值