手写简易的MiniVue(03-实现createApp)

858 阅读2分钟

前言

上文实现渲染器系统

在前面两章中我们实现了 响应式系统渲染器系统 ,这章节我们来实现 createApp 函数,我们要实现的 createApp 函数是一个工厂函数,用于创建一个应用程序实例。它接受一个根组件作为参数,并返回一个对象,该对象具有一个 mount 方法。mount 方法接受一个选择器字符串作为参数,用于指定应用程序将要挂载到哪个 DOM 元素上。在 mount 方法内部,createApp 函数使用了一个 effect 函数来监听根组件的渲染函数。如果应用程序尚未挂载,则调用根组件的渲染函数并将其返回的虚拟 DOM 对象挂载到指定的 DOM 元素上。如果应用程序已经挂载,则调用根组件的渲染函数并使用 patch 函数将新的虚拟 DOM 对象与旧的虚拟 DOM 对象进行比较并更新 DOM 元素。

话不多说,让我们开始把!

实现 createApp 函数

createApp 函数的作用我们在前言中已经讲了,直接上代码:

function createApp(rootComponent) {
  // 创建应用程序实例的工厂函数,接受一个根组件作为参数
  return {
    mount(selector) {
      // 挂载方法,接受一个选择器字符串作为参数
      const root = document.querySelector(selector); // 获取要挂载到的 DOM 元素
      let isMounted = false; // 标记应用程序是否已经挂载
      let oldVnode = null; // 旧的虚拟 DOM 对象
​
      effect(() => {
        // 使用 effect 函数监听根组件的渲染函数
        if (!isMounted) {
          // 如果应用程序尚未挂载
          oldVnode = rootComponent.render(); // 调用根组件的渲染函数并将其返回的虚拟 DOM 对象赋值给 oldVnode
          mount(oldVnode, root); // 将 oldVnode 挂载到指定的 DOM 元素上
          isMounted = true; // 将 isMounted 标记为 true
        } else {
          // 如果应用程序已经挂载
          const newVnode = rootComponent.render(); // 调用根组件的渲染函数并将其返回的虚拟 DOM 对象赋值给 newVnode
          patch(oldVnode, newVnode); // 使用 patch 函数将新的虚拟 DOM 对象与旧的虚拟 DOM 对象进行比较并更新 DOM 元素
          oldVnode = newVnode; // 将 newVnode 赋值给 oldVnode
        }
      });
    },
  };
}

每一行已经标上了注释,我也就不过多讲解。直接让我们来测试吧:

const App = {
  data: reactive({
    count: 0,
  }),
  render() {
    return h(
      "div",
      {
        style: {
          width: "200px",
          height: "200px",
          backgroundColor: "red",
        },
      },
      [
        h("h2", null, this.data.count),
        h(
          "button",
          {
            onClick: () => {
              this.data.count++;
            },
          },
          "+1"
        ),
      ]
    );
  },
};
​
createApp(App).mount("#root");
​

效果:

xwzw7-54fhg.gif

总结

至此,我们要实现的 MiniVue 的功能都已经实现了,尽管我们所实现的功能和代码都很简单,但对于初学者来说也是了解vue3的一种算作“开胃小菜吧”,之后的文章我会带着大家一步一步实现vue3内部的API。让我们一起期待吧,共勉!