Vue实例创建和挂载的详细过程
作者:疯狂的沙粒
在 Vue.js 中,实例的挂载是一个非常重要的过程,它决定了 Vue 实例如何与 DOM 进行交互,通过分析 Vue 源码,特别是 Vue 的构建函数和生命周期,我们可以了解挂载过程的详细步骤,需要的朋友可以参考下
1. Vue 实例创建和挂载的过程概述
Vue 实例的挂载过程涉及多个关键步骤,包括创建实例、编译模板、初始化数据和事件绑定等。它的核心流程大致如下:
- 初始化 Vue 实例:在
new Vue()
调用时,Vue 实例会创建并初始化相关的属性,如data
、computed
、methods
等。 - 初始化生命周期:Vue 会初始化生命周期钩子,包括
beforeCreate
、created
、beforeMount
、mounted
等。 - 编译模板:Vue 会解析传入的模板,生成虚拟 DOM(VNode)。
- 渲染:将虚拟 DOM 转换为真实的 DOM,最终将 Vue 实例挂载到指定的 DOM 节点上。
- 更新:在响应式数据变化时,Vue 会触发更新,重新渲染组件。
2. 分析源码:Vue 实例的创建与挂载过程
我们从 Vue 2.x 的源码分析 Vue 实例的挂载过程。以下是大致的分析步骤。
2.1 Vue 实例的构建函数
首先,我们来看 Vue 的构建函数,它通常是通过 new Vue(options)
来实例化 Vue 对象的。options
对象包含了组件的配置项,比如 el
、data
、template
等。
function Vue(options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue)) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options); }
在构造函数中,调用了 this._init(options)
,也就是实例化时 Vue 会调用内部的 _init
方法进行初始化。
2.2 Vue 的 _init 方法
Vue.prototype._init = function (options) { const vm = this; vm._uid = uid$1++; // 生成唯一 ID vm._isVue = true; // 标记 Vue 实例 vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {} ); // 合并构造函数默认选项和用户传入的选项 vm._renderProxy = vm; // 渲染代理 vm._self = vm; // 指向自己 initLifecycle(vm); // 初始化生命周期 initEvents(vm); // 初始化事件 initRender(vm); // 初始化渲染 callHook(vm, 'beforeCreate'); // 调用生命周期钩子 beforeCreate initState(vm); // 初始化数据、计算属性等 initInjections(vm); // 处理依赖注入 callHook(vm, 'created'); // 调用生命周期钩子 created if (vm.$options.el) { vm.$mount(vm.$options.el); // 挂载实例 } };
- 生命周期的初始化:在
_init
方法中,Vue 会进行生命周期的初始化,并调用beforeCreate
和created
钩子。 - 渲染代理:
_renderProxy
用于实现模板访问this
时的代理。 $mount
:如果传入了el
选项,Vue 会调用$mount
方法来挂载实例。
2.3 Vue 的 $mount 方法
挂载的核心方法是 $mount
,它接受一个 DOM 元素或选择器字符串,并将 Vue 实例与这个 DOM 节点进行绑定。
Vue.prototype.$mount = function (el, hydrating) { el = el && query(el); // 如果传入了 el,进行选择并获取 DOM 元素 if (el === document.body || el === document.documentElement) { warn('Do not mount Vue to <html> or <body> - mount to normal elements instead.'); return; } const options = this.$options; if (!options.render) { let template = options.template; if (template) { if (typeof template === 'string') { // 编译模板 template = compileToFunctions(template, this); } } else if (el) { // 没有模板时,从 DOM 中获取内容作为模板 template = el.outerHTML; } options.render = template ? compileToFunctions(template, this) : createEmptyVNode; } return mountComponent(this, el, hydrating); };
- DOM 查询:首先,
el
被解析成 DOM 元素。 - 模板编译:如果没有传入渲染函数 (
render
),Vue 会尝试从模板字符串中编译生成渲染函数。 mountComponent
:最后,调用mountComponent
来进行组件的挂载。
2.4 mountComponent 方法
mountComponent
是挂载组件的核心方法,它会调用 vm.$el
将实例挂载到指定的 DOM 上。
function mountComponent(vm, el, hydrating) { vm.$el = el; callHook(vm, 'beforeMount'); let updateComponent; // 这里通过 render 函数来渲染视图 updateComponent = function () { vm._update(vm._render(), hydrating); }; // 调用 Vue 的渲染函数,执行视图更新 new Watcher(vm, updateComponent, noop, { before: callHook.bind(vm, 'beforeUpdate') }, true); callHook(vm, 'mounted'); return vm; }
- 调用
beforeMount
:在渲染之前,会先执行beforeMount
生命周期钩子。 - 渲染和更新:
updateComponent
会触发vm._update
方法进行视图更新。_render()
是用于生成虚拟 DOM 的方法,它会调用渲染函数。 - Watcher:Vue 通过
Watcher
来观察响应式数据的变化,并在数据变化时触发更新。
2.5 Vue 的 _update 方法
_update
方法会根据虚拟 DOM 的变化,重新渲染并更新 DOM。
Vue.prototype._update = function (vnode, hydrating) { const vm = this; const prevEl = vm.$el; const prevVnode = vm._vnode; vm._vnode = vnode; if (!prevVnode) { // 初次渲染 vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */); } else { // 更新渲染 vm.$el = vm.__patch__(prevVnode, vnode); } // 更新生命周期钩子 callHook(vm, 'updated'); };
- 虚拟 DOM 比对:
_update
会执行虚拟 DOM 与真实 DOM 的比对,更新页面内容。 - 生命周期钩子:更新后,会调用
updated
生命周期钩子。
3. 总结 Vue 实例挂载的过程
Vue 实例的挂载过程包含以下几个主要步骤:
- 初始化实例:通过
new Vue(options)
创建 Vue 实例,调用_init
方法进行初始化。 - 编译模板:如果没有传入
render
函数,Vue 会通过模板字符串生成渲染函数。 - 挂载组件:通过
$mount
方法将 Vue 实例挂载到指定的 DOM 元素上。 - 渲染更新:通过
_update
方法更新 DOM,生成新的视图。 - 生命周期钩子:在每个阶段会触发相应的生命周期钩子函数(如
beforeCreate
、created
、beforeMount
、mounted
等)。
通过以上分析,我们可以理解 Vue 实例挂载的完整过程,以及其中涉及的关键函数和生命周期钩子。
到此这篇关于Vue实例创建和挂载的详细过程的文章就介绍到这了,更多相关Vue实例创建和挂载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!