2024年最新vue2源码解析——new Vue()这个过程究竟做了什么?,快手面试java

最后

推荐一些系统学习的途径和方法。

路线图

每个Web开发人员必备,很权威很齐全的Web开发文档。作为学习辞典使用,可以查询到每个概念、方法、属性的详细解释,注意使用英文关键字搜索。里面的一些 HTML,CSS,HTTP 技术教程也相当不错。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

HTML 和 CSS:

html5知识

css基础知识

main.js 中创建一个 Vue 实例,并将 App.vue 组件渲染到 id 为 app 的 DOM 元素上,而这个 DOM 元素正是 index.html 中提供的。因此,最终 Vue 应用会被挂载到 index.html 中 id 为 app<div> 元素上,用户将在浏览器中看到 Vue 应用渲染的内容。

App.vue 中的 #app:App.vue 文件中,通常会包含应用的根组件,这个根组件会作为整个应用的入口。为了将根组件挂载到 index.html 中的 #app 元素上,通常会在 App.vue 文件中定义一个与 index.html 中的 #app 相对应的容器,以便将根组件挂载到正确的位置。

<!--index.html-->

<!DOCTYPE html>
<html lang="">
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

<!--app.vue-->

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
//main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

对比生命周期流程图分析$mount挂载过程

使用 m o u n t 挂载, ‘ mount挂载,` mount挂载,mount方法接收一个选择器字符串或一个 DOM 元素作为参数,用于指定 Vue 实例挂载的目标元素。调用 m o u n t ‘ 方法后, V u e 实例会将自身挂载到指定的 D O M 元素上,从而开始管理该 D O M 元素及其子元素的状态和数据。如果在创建 V u e 实例时没有提供 ‘ r e n d e r ‘ 函数, V u e 会根据实例选项中的 ‘ t e m p l a t e ‘ 或挂载元素的 H T M L 内容来编译模板。当调用 ‘ mount` 方法后,Vue 实例会将自身挂载到指定的 DOM 元素上,从而开始管理该 DOM 元素及其子元素的状态和数据。如果在创建 Vue 实例时没有提供 `render` 函数,Vue 会根据实例选项中的 `template` 或挂载元素的 HTML 内容来编译模板。当调用 ` mount方法后,Vue实例会将自身挂载到指定的DOM元素上,从而开始管理该DOM元素及其子元素的状态和数据。如果在创建Vue实例时没有提供render函数,Vue会根据实例选项中的template或挂载元素的HTML内容来编译模板。当调用mount` 方法时,Vue 会对模板进行编译,生成渲染函数,用于将数据渲染到 DOM 中

组件实例

为什么要区分根实例和vue实例呢?

因为很多人对这个new Vue很懵逼。在业务代码里,拢共就写了一个new Vue。但是你在写.vue页面的时候是不是每个组件都有一套生命周期钩子函数可以用,涉及挂载、更新、卸载等?可是我们没有显示的使用new Vue()创建组件实例啊?

在官方给的解释中说道:所有的vue组件都是Vue实例!

组件实例和根实例的区别

根实例是整个Vue应用的入口点,负责管理整个应用;而组件实例是构成应用的独立模块,每个组件实例之间相互独立,有自己的生命周期钩子函数和状态。在Vue中,所有的组件都是Vue实例,但是根实例和组件实例在功能和作用上有所区别。这个区别主要体现在以下几个方面:

  1. 根实例 vs 组件实例:

    • 根实例是整个Vue应用的最顶层实例,负责管理整个应用的数据和行为。
    • 组件实例是Vue应用中的组件,每个组件都是一个独立的Vue实例,拥有自己的数据、方法和生命周期钩子函数。
  2. 创建方式:

    • 根实例通常是在 main.js 中通过 new Vue() 创建的。
    • 组件实例是在组件定义中通过 components 属性注册或者在单文件组件中直接定义的。
  3. 生命周期钩子函数:

    • 根实例拥有完整的生命周期钩子函数,包括 beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed
    • 组件实例也有自己的生命周期钩子函数,如 beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed,用于控制组件的初始化、更新和销毁等过程。
  4. 组件复用和嵌套:

    • 组件实例可以被复用和嵌套,每个组件实例之间相互独立,有自己的作用域和状态。
    • 根实例是整个应用的顶级实例,负责管理所有组件实例,并提供全局配置和状态管理。
组件实例的new Vue过程怎么理解 ?

在Vue中,组件实例的创建并不需要显式地使用 new Vue(),而是通过Vue组件系统来创建组件实例。当我们在Vue应用中定义一个组件时,Vue会在内部帮我们处理组件实例的创建和管理。在Vue中,组件实例的创建过程大致可以分为以下几个步骤:

  1. 组件定义: 我们在Vue应用中定义一个组件,可以是全局注册的组件,也可以是局部注册的组件(在父组件中注册)。
  2. 组件实例化: 当组件在模板中被使用时,Vue会根据组件定义自动实例化组件。这个过程是由Vue的编译器负责的。
  3. 虚拟DOM的创建: Vue会根据组件的模板(template)生成虚拟DOM(Virtual DOM)。
  4. 挂载组件: Vue会将生成的虚拟DOM挂载到实际的DOM元素上,这个过程是在组件的生命周期钩子函数中的 mounted 钩子中完成的。
  5. 更新组件: 当组件的数据发生变化时,Vue会重新渲染组件,并更新视图。这个过程是在组件的生命周期钩子函数中的 updated 钩子中完成的。
  6. 销毁组件: 当组件不再需要时(比如组件被销毁或者不再显示),Vue会在适当的时机销毁组件实例,释放组件占用的资源。这个过程是在组件的生命周期钩子函数中的 beforeDestroydestroyed 钩子中完成的。

总的来说,组件实例的创建过程是由Vue自动管理的,我们只需要定义好组件,然后在需要的地方使用组件即可。Vue会负责处理组件实例的创建、更新和销毁等过程,我们不需要手动去实例化组件。这种抽象的方式让我们可以更专注于组件的功能和交互,而不必过多关注底层的实例化细节。

new Vue生命周期过程

在了解了new Vue是干什么的,以及组件实例和根实例的作用,再来看vue组件实例/根实例的生命周期就有思路了。Vue 实例的生命周期过程可以分为以下几个阶段:

  1. 初始化阶段(Initialization):
  • beforeCreate:在实例初始化之后,数据观测和事件配置之前被调用。
  • created:实例已经创建完成,数据观测和事件配置已完成,但尚未挂载到 DOM 上。
  1. 模板编译阶段(Template Compilation):
  • beforeMount:在挂载开始之前被调用:相关的 render 函数首次被调用。
  • mounted:实例已经挂载到 DOM 上后被调用,这时可以访问到DOM元素。
  1. 更新阶段(Updating):
  • beforeUpdate:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
  • updated:数据更新后调用,发生在虚拟 DOM 重新渲染和打补丁之后。
  1. 销毁阶段(Destruction):
  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
  • destroyed:实例销毁后调用。在这一步,Vue 实例的所有指令已经解绑,所有事件监听器已经移除,所有子实例也已经被销毁。

在 Vue 实例的生命周期中,开发者可以利用这些生命周期钩子函数来执行各种操作,比如在数据初始化前后执行某些逻辑、在 DOM 渲染前后执行某些操作、在组件销毁前后清理资源等。生命周期钩子函数提供了丰富的扩展能力,可以帮助开发者更好地控制应用的行为。

源码相关术语解释

源码中的类、构造函数、属性、方法、实例的解释

Vue:表示vue的构造函数

Vue.prototype.**:表示给构造函数增加**方法

vm:表示vue实例

vm.**:获取vm实例的属性或调用vm实例的方法

vm. o p t i o n s : 获取 v m 实例的 options:获取vm实例的 options:获取vm实例的options属性

vnode:虚拟节点

vm._render:渲染函数,将模板转换虚拟dom

vm._update:调用组件更新方法

Watcher类:监听模板变化的监听器;监听vm数据变化重新渲染。数据变化执行updated

hook:生命周期名字

callHook(vm, ‘***’) :在当前vue组件实例中,调用某个生命周期钩子注册的所有回调函数。

Vue构造函数和vm实例

vue实例,在源码中通过new function Vue构造函数的方式生成。源码通过mixin混入,将外部定义的Vue.prototype.**原型方法与Vue构造函数结合,扩展Vue的方法。

Vue原型总共提供了下面方法:事件相关$on$once$off$emit;初始化相关_init;更新相关_update$forceUpdate$destroy;渲染相关 n e x t T i c k r e n d e r ;状态相关 nextTick\\_render;状态相关 nextTickrender;状态相关set$delete等。挂载$mount方法

vm可以访问哪些属性和方法呢 ?

在vue的类型定义,component.ts文件里可以看到vm的类型

vm.$options——获取vm实例相关属性

vm.$options:在源码中大量出现!用于 访问和操作 Vue 实例的初始化选项,在运行时方便地获取到实例的配置信息,并根据这些信息进行相应的处理。

可以通过$options获取vm实例的哪些属性呢?

o p t i o n s 的类型定义 C o m p o n e n t O p t i o n s 可以看到, options的类型定义ComponentOptions可以看到, options的类型定义ComponentOptions可以看到,options对象可以访问的属性几乎包括了vm实例所有的事件、属性、方法。包括选项式api提供的data\props\computed\method\watch等;dom相关的挂载点、render函数等;生命周期相关的钩子函数;指令,依赖注入以及一些vm的私有属性。

源码解析

初始化事件绑定和父子关系

源码关于实例化过程,在 vue-main\src\core\instance\index.ts中,可以看到Vue的构造函数,function Vue()。同时,下面还做了混入方法,混入方法就是给Vue原型增加方法。

在vue-main\src\core\instance\init.ts文件中可以看到额外扩展了Vue原型的__init方法

initLifecycle方法

initLifecycle 方法主要完成了初始化了父子组件关系:

  • 将当前组件的父组件设置为传入的 parent 组件。
  • 将当前组件添加到父组件的子组件列表中。

初始化组件的生命周期相关属性:

初始化了 _isMounted 属性,用来表示组件是否已经挂载。初始化了 _isDestroyed 属性,用来表示组件是否已经销毁。初始化了 _isBeingDestroyed 属性,用来表示组件是否正在被销毁。初始化了 _inactive 属性,用来表示组件是否处于非活动状态。

initEvents方法

initEvents 主要负责初始化事件相关的数据结构,并处理父组件传递的事件监听器,确保组件在初始化时能够正确处理事件。initEvents 函数主要完成了以下几个步骤:

  1. 创建了一个空对象 _events 用来存储事件监听器。
  2. _hasHookEvent 标记设置为 false,用来表示当前组件是否有钩子函数相关的事件。
  3. 检查是否有父组件传递的事件监听器,如果有的话则调用 updateComponentListeners 函数来更新组件的监听器。

初始化依赖注入和响应式数据

initInjections方法

initInjections 函数主要负责解析注入属性的值,为这些注入属性设置响应式,并在开发环境下给出警告,防止直接修改注入属性导致不可预料的问题

initState方法

initState 函数主要负责初始化组件的 props、setup、methods、data、computed 和 watch 等状态,为组件的各种状态做准备工作,以便在组件实例化时能够正确地使用这些状态。

在beforeCreate钩子的时候我们没有对propsmethodsdatacomputedwatch上的数据的访问权限。在created中才可以

initProvide方法

initProvide 函数的作用是初始化组件的 provide 数据,将 provide 数据提供给组件的后代组件使用。这样可以在组件树中实现跨层级传递数据,为子组件提供共享的数据或方法。

模板渲染

在created方法后,beforeMount之前,执行的是模板转换为render函数的过程。new Vue示例图中没有el属性才会去调 m o u n t 方法。但是在源码中, c r e a t e d 钩子之后,判断 e l 存在也会去调 mount方法。但是在源码中,created钩子之后,判断el存在也会去调 mount方法。但是在源码中,created钩子之后,判断el存在也会去调mount方法。

$mount方法

m o u n t 中进行模板渲染,在源码中重写 mount中进行模板渲染, 在源码中重写 mount中进行模板渲染,在源码中重写mount方法。如果vue的$options上有render方法,则返回。否则,根据template生成render函数。没有template的话,调el挂载的html解析为template模板。不用进行render函数生成。

组件挂载

组件挂载的过程核心部分在mountComponent方法中实现。

mountCompontent方法

每个组件有对应的Watcher,数值变化会触发其update函数导致重新渲染mountComponent核心就是实例化一个渲染watcher,在它的回调函数中调用updateComponent方法。

updateComponent更新模板方法,其中有两个核心方法:vm_render用于生成虚拟Dom,和vm_.update将虚拟dom映射到真实dom。

在mountComponent方法里,使用vm.$el接收el变量。执行beforeMount钩子函数。设置更新模板逻辑updateComponent方法。设置watcher监听选项,内置了beforeUpdate方法。

总结
  • 对于框架原理只能说个大概,真的深入某一部分具体的代码和实现方式就只能写出一个框架,许多细节注意不到。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  • 算法方面还是很薄弱,好在面试官都很和蔼可亲,擅长发现人的美哈哈哈…(最好多刷一刷,不然影响你的工资和成功率???)

  • 在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。

  • 要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!

第一次跳槽十分忐忑不安,和没毕业的时候开始找工作是一样的感受,真的要相信自己,有条不紊的进行。如果有我能帮忙的地方欢迎随时找我,比如简历修改、内推、最起码,可以把烦心事说一说,人嘛都会有苦恼的~

祝大家都有美好的未来,拿下满意的 offer。

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值