vue3剖析之简版实现

简介: 文章主要阐述vue3的API用法,以及简单地实现一个vue3。带大家感受一下vue3与之前vue2的区别。以及简单带大家揭秘源码中vue3初始化的一个流程。

网络异常,图片无法展示
|


hello 大家好,🙎🏻‍♀️🙋🏻‍♀️🙆🏻‍♀️

我是一个热爱知识传递,正在学习写作的作者,ClyingDeng 凳凳!


最近,由于我的第一个vue3 + ts的正式项目,已经进入验收阶段。听你们老说vue3、vue3的,我就想着去看看vue3到底和vue2有啥区别。🤷🏻‍♀️🤷🏻‍♀️🤷🏻‍♀️


文章主要阐述vue3的API用法,以及简单地实现一个vue3。带大家感受一下vue3与之前vue2的区别。以及简单带大家揭秘源码中vue3初始化的一个流程。


🍹准备工作


要想看看vue3内部的源码是咋搞得,首先跟vue2源码剖析一样,先从github上下一份源码到本地。 接着就是安装依赖:


yarn --ignore-scripts


在你执行命令的时候可能会遇到node版本过低的错误:

网络异常,图片无法展示
|


解决此问题可以升级自己的node版本,或者忽略该engine。 如果选择忽略的话可以设置


yarn config set --ignore-engines true


然后执行依赖安装。 依赖安装完成后,编译打包生成vuejs文件:


yarn dev


需要调试的话,可以在packages\vue\examples文件下建立测试文件。引用打包后的vue文件,可以应用packages\vue\dist\vue.global.js


🍲vue3用法


vue3的特性我就不多阐述了,就vue3的用法而言,更倾向于函数式编程,通过对外暴露Vue中的createApp()API,以工厂函数的方式创建了一个应用程序实例。相比较vue2的new Vue实例,更加贴切。


在源码文件中,我们新建一个init.html文件。


<script src="../dist/vue.global.js"></script>
 <body>
  <div id="app">{{name}}</div>
  <script>
    const { createApp } = Vue
    const app1 = createApp({
      data() {
        return {
          name: 'clying'
        }
      },
      setup() {
        return {
          name: 'deng'
        }
      }
    }).mount('#app')
  </script>
</body>


根据上例,我们可以看出vue3是即支持Composition API,也支持Options API,两者可以同时使用。


但是,我们可以看到在data和setup中,我同时使用了一个name变量进行赋值。那么页面中会展示哪一个呢?


3!2!1!上答案:

网络异常,图片无法展示
|


可以明显看出composition-api中setup优先级更高。


网络异常,图片无法展示
|


当然也可以在源码中的packages\runtime-core\src\componentPublicInstance.ts看到,通过switch先判断setup中的变量是否存在,然后再去判断data中的变量。所以setup中变量的优先级会高于data中的变量。


🍖实现


通过上面的用法,我们可以知道vue3中会对外暴露一个Vue变量,内部存在createAppreactive等方法。


在此,我们先实现vue3的初始化框架。就createApp而言,它会接收用户传入的参数:data()setup()等,最后进行实例挂载mount。所以在createApp中会接收一些参数options、内部还会存在mount方法。


const Vue = {
    createApp(options) {
      return {
        mount(selector) { //解析、获取render、挂载
        }
      }
    }
}


在mount中通过selector获取到宿主元素。 接下来就是对模板的编译,由于将template编译AST后,依旧要转成render函数。在此我们简化操作,在编译时直接返回一个render。


mount(selector) { //解析、获取render、挂载
  const parent = document.querySelector(selector)
  console.log(parent);
  if (!options.render) {
    // 编译返回render
    options.render = this.compileToFunction(parent.innerHTML)
  }
},
compileToFunction(template) {
  return function render() {
    const h = document.createElement('div')
    h.textContent = this.name
    return h
  }
}


拿到render之后,执行它,将其添加到宿主元素中,将老的节点删除。 在执行render的时候,我们需要注意它的this指向。如果给它绑定data,那么它展示的就会使data中的name。


mount(selector) { //解析、获取render、挂载
  const parent = document.querySelector(selector)
  console.log(parent);
  if (!options.render) {
    // 编译返回render
    options.render = this.compileToFunction(parent.innerHTML)
  }
  // 执行render 
  const el = options.render.call(options.data())
  parent.innerHTML = ''
  parent.appendChild(el)
},

网络异常,图片无法展示
|
可以看到页面上展示的是 clying。反之,如果绑定的是 options.setup(),那么页面上出现的就是 deng


对于vue3的用法,我们知道setup的优先级是高于data的。那我们可以使用代理啊,将两者的属性变量,通过代理的方式,糅合到一起,优先考虑setup。当访问相同name时,实际访问的就是setup中的name。


mount(selector) { //解析、获取render、挂载
  const parent = document.querySelector(selector)
  console.log(parent);
  if (!options.render) {
    // 编译返回render
    options.render = this.compileToFunction(parent.innerHTML)
  }
  if (options.setup) {
    this.setupState = options.setup()
  }
  if (options.data) {
    this.data = options.data()
  }
  this.proxy = new Proxy(this, {
    get(target, key) {
      if (key in target.setupState) {
        return target.setupState[key]
      } else if (key in target.data) {
        return target.data[key]
      }// 还可能存在props、watch等其他同名变量
    }, 
    set(target, key, value, newVal) {
      console.log(target, key, value, newVal);
    }
  })
  // 执行render  this.proxy就是整合setup和data的上下文
  const el = options.render.call(this.proxy)
  console.log(el, options.render);
  parent.innerHTML = ''
  parent.appendChild(el)
},


在proxy的get中,先看setup中是否存在目标属性,如果存在的话返回的就是setup中的属性变量,否则就是data中的。在渲染的时候,直接将整合的变量集传入即可。当然proxy中也会存在set方法,需要先代理,然后在外部获取变量做值得修改才能触发,在此有兴趣的同学可以自行研究哦!


到此vue3的简单实现到此就结束拉。感兴趣的同学可以关注 Vue源码初识专栏或者关注我哦!会持续输出vue相关知识哦(●'◡'●)。 如果不足,请多指教。

目录
相关文章
|
3月前
|
JavaScript 前端开发 安全
Vue 3
Vue 3以组合式API、Proxy响应式系统和全面TypeScript支持,重构前端开发范式。性能优化与生态协同并进,兼顾易用性与工程化,引领Web开发迈向高效、可维护的新纪元。(238字)
658 139
|
3月前
|
缓存 JavaScript 算法
Vue 3性能优化
Vue 3 通过 Proxy 和编译优化提升性能,但仍需遵循最佳实践。合理使用 v-if、key、computed,避免深度监听,利用懒加载与虚拟列表,结合打包优化,方可充分发挥其性能优势。(239字)
324 1
|
8月前
|
缓存 JavaScript PHP
斩获开发者口碑!SnowAdmin:基于 Vue3 的高颜值后台管理系统,3 步极速上手!
SnowAdmin 是一款基于 Vue3/TypeScript/Arco Design 的开源后台管理框架,以“清新优雅、开箱即用”为核心设计理念。提供角色权限精细化管理、多主题与暗黑模式切换、动态路由与页面缓存等功能,支持代码规范自动化校验及丰富组件库。通过模块化设计与前沿技术栈(Vite5/Pinia),显著提升开发效率,适合团队协作与长期维护。项目地址:[GitHub](https://github.com/WANG-Fan0912/SnowAdmin)。
1103 5
|
4月前
|
开发工具 iOS开发 MacOS
基于Vite7.1+Vue3+Pinia3+ArcoDesign网页版webos后台模板
最新版研发vite7+vue3.5+pinia3+arco-design仿macos/windows风格网页版OS系统Vite-Vue3-WebOS。
497 11
|
3月前
|
JavaScript 安全
vue3使用ts传参教程
Vue 3结合TypeScript实现组件传参,提升类型安全与开发效率。涵盖Props、Emits、v-model双向绑定及useAttrs透传属性,建议明确声明类型,保障代码质量。
374 0
|
5月前
|
缓存 前端开发 大数据
虚拟列表在Vue3中的具体应用场景有哪些?
虚拟列表在 Vue3 中通过仅渲染可视区域内容,显著提升大数据列表性能,适用于 ERP 表格、聊天界面、社交媒体、阅读器、日历及树形结构等场景,结合 `vue-virtual-scroller` 等工具可实现高效滚动与交互体验。
560 1
|
5月前
|
缓存 JavaScript UED
除了循环引用,Vue3还有哪些常见的性能优化技巧?
除了循环引用,Vue3还有哪些常见的性能优化技巧?
331 0
|
6月前
|
JavaScript
vue3循环引用自已实现
当渲染大量数据列表时,使用虚拟列表只渲染可视区域的内容,显著减少 DOM 节点数量。
157 0
|
8月前
|
JavaScript API 容器
Vue 3 中的 nextTick 使用详解与实战案例
Vue 3 中的 nextTick 使用详解与实战案例 在 Vue 3 的日常开发中,我们经常需要在数据变化后等待 DOM 更新完成再执行某些操作。此时,nextTick 就成了一个不可或缺的工具。本文将介绍 nextTick 的基本用法,并通过三个实战案例,展示它在表单验证、弹窗动画、自动聚焦等场景中的实际应用。
746 17
|
9月前
|
JavaScript 前端开发 算法
Vue 3 和 Vue 2 的区别及优点
Vue 3 和 Vue 2 的区别及优点

热门文章

最新文章