vue3源码剖析之简单实现方法

 更新时间:2021年09月07日 11:51:58   作者:ClyingDeng  
源码的重要性相信不用再多说什么了吧,特别是用Vue 框架的,一般在面试的时候面试官多多少少都会考察源码层面的内容,下面这篇文章主要给大家介绍了关于vue3源码剖析之简单实现的相关资料,需要的朋友可以参考下

前言

最近,由于我的第一个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变量,内部存在createApp、reactive等方法。

在此,我们先实现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源码剖析之简单实现的文章就介绍到这了,更多相关vue3源码剖析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue+Element实现动态生成新表单并添加验证功能

    Vue+Element实现动态生成新表单并添加验证功能

    这篇文章主要介绍了Vue+Element实现动态生成新表单并添加验证功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-05-05
  • Vue3使用indexDB缓存静态资源的示例代码

    Vue3使用indexDB缓存静态资源的示例代码

    IndexedDB 是一个浏览器内建的数据库,它可以存放对象格式的数据,默认情况下,浏览器会将自身所在的硬盘位置剩余容量全部作为indexedDB的存储容量,本文给大家介绍了Vue3使用indexDB缓存静态资源,需要的朋友可以参考下
    2024-10-10
  • Vite+Electron快速构建VUE3桌面应用的实现

    Vite+Electron快速构建VUE3桌面应用的实现

    本文主要介绍了Vite+Electron快速构建VUE3桌面应用的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • 在Vue中实现网页截图与截屏功能详解

    在Vue中实现网页截图与截屏功能详解

    在Web开发中,有时候需要对网页进行截图或截屏,Vue作为一个流行的JavaScript框架,提供了一些工具和库,可以方便地实现网页截图和截屏功能,本文将介绍如何在Vue中进行网页截图和截屏,需要的朋友可以参考下
    2023-06-06
  • Vue2.0生命周期的理解

    Vue2.0生命周期的理解

    这篇文章主要为大家介绍了Vue2.0生命周期,思考与理解“el被新创建的vm.$el替换”这句话,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • 深入解析Vue的自定义指令

    深入解析Vue的自定义指令

    这篇文章主要介绍了深入解析Vue的自定义指令,自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑,一个自定义指令由一个包含类似组件生命周期钩子的对象来定义,需要的朋友可以参考下
    2023-05-05
  • Vue开发实现吸顶效果的示例代码

    Vue开发实现吸顶效果的示例代码

    这篇文章主要介绍了Vue开发实现吸顶效果的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Nuxt3项目搭建过程(Nuxt3+element-plus+scss详细步骤)

    Nuxt3项目搭建过程(Nuxt3+element-plus+scss详细步骤)

    这篇文章主要介绍了Nuxt3项目搭建(Nuxt3+element-plus+scss详细步骤),本次记录一次使用Nuxt3搭建前端项目的过程,内容包含Nuxt3的安装,基于Vite脚手架(默认)构建的vue3项目,element-plus的安装配置,scss的安装,目录结构的创建和解释,需要的朋友可以参考下
    2022-12-12
  • VueCLI通过process.env配置环境变量的实现

    VueCLI通过process.env配置环境变量的实现

    本文主要介绍了VueCLI通过process.env配置环境变量的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Vue使用sign-canvas实现在线手写签名的实例

    Vue使用sign-canvas实现在线手写签名的实例

    sign-canvas 一个基于 canvas 开发,封装于 Vue 组件的通用手写签名板(电子签名板),支持 pc 端和移动端,本文给大家分享Vue使用sign-canvas实现在线手写签名,感兴趣的朋友一起看看吧
    2022-05-05

最新评论