vue页面渲染顺序,vue后端渲染方案
本文主要介绍vue第一次渲染的全过程。通过示例代码进行了非常详细的介绍,对大家的学习或者工作都有一定的参考价值。有需要的朋友下面和边肖一起学习。
目录
1、vue初始化vue入口文件完整版和运行时版的区别1.1、src/core/instace/index.js1.2、src/core/index.js1.3、src/platforms/web/runtime/index . js 1.4、src/platforms/web/Entry-runtime-with-compiler . js 1.5、vue初始化总结2、vue构造函数执行2.1、beforeCreate hook 2.2、created hook 2.3、$mount函数2看来这个问题在很多朋友心中可能还是比较模糊的。今天,我们来详细看看。
要了解vue第一次渲染的全过程,应该从哪里入手?显然,我们应该从导入文件开始,即main.js
1、vue初始化
首先我们来看main.js第一个也是最关键的肯定是vue的引入。
从“vue”导入vue
其实vue打包后,dist文件夹里有好几个版本,分别是通用版本(UMD)中的完整版vue.js:和运行时版vue.runtime.jsCommonJs版本中的完整版vue.common.js和运行时版vue.runtime.common.js:
ES模块版本:完整版vue.esm.js和运行时版vue.runtime.esm.js in。
一般在vue2.6之后,我们用vue/cli创建的项目都使用vue.runtime.esm.js的运行时版本
即引入vue时会引入vue.esm.js版本。
那么引入vue后,vue中的相关代码会被执行吗?vue源代码中的哪个代码是新执行的(导入的vue是vue源代码中打包的vue),我们首先要知道入口文件在哪里。
vue入口文件
vue的入口文件主要在vue源代码结构的src/platforms/web下。
打包vue时,可以选择不同的vue导入文件进行打包,不同导入文件打包的vue版本是不一样的。
这里主要说完整版的entry-runtime-with-compiler.js。
我们先来了解一下完整版和运行版的区别。
完整版和运行时版本的区别
完整版是运行时版本编译器的组合。
运行时版没有编译器,即没有模板编译功能,主要用于创建vue实例和渲染虚拟dom。体积小,重量轻(编译器编译器有3000多行代码)
你是什么意思,也就是
身体
div id=应用程序
p我是index.html的内容/p
/div
/body
新Vue({
Template: div I是由template template /div呈现的内容
}).$ mount(“# app”)
以上情况,
如果是完整版的vue,有编译器,会把new Vue传入的模板编译成渲染函数,赋给options的render属性。然后$mount之后,render函数会被渲染成一个虚拟dom,然后虚拟dom会被转换成一个真实的dom,所以最后的页面会出现我是template模板渲染出来的内容这句话。原句将被覆盖。
如果是运行时版本,没有编译器,模板中的内容不会被编译,那么页面上将只存在原来的dom。
我们继续往下看。
找到入口文件后,我们开始查看将执行什么。
可以看到,导入文件是先导入到vue中,然后经过一些处理,最后导出vue。
我们先通过导入vue的路径,一步步找出vue构造函数是在哪里创建的。如上图,vue是从runtime/index导入的,我们去看看runtime/index。
这个文件也是如此。经过一些处理后,vue被导入,然后vue被导出。让我们继续寻找核心/索引。
这个文件也是如此。让我们继续向上看。/实例/索引
在这里,我们找到了我们的vue构造函数的创建,它位于源代码的src/core/instance/index.js文件中。
那么,从上面的引用关系我们可以发现,vue引入项目后,第一个要执行的文件的顺序是
src/core/instace/index.js===1
src/core/index.js===2
src/platforms/web/runtime/index . js===3
src/platforms/web/entry-runtime-使用编译器。联署材料4
那么,我们再来看,每个文件都执行了些什么,
首先src/core/instace/index.js
1.1、src/core/instace/index.js
首先,此文件定义了视图(视图)构造函数,并初始化了一些视图(视图)的实例属性和实例方法,即,在视图。原型原型下新增了各种方法和属性
下面,我们具体来看下,每一个方法具体初始化了视图(视图)的哪些实例属性或方法
1 .1 .1、initmixin(视图)
1.1.2状态混合(视图)
1 .1 .3、事件smixin(视图)
1 .1 .生命周期蛋白(视图)
1 .1 .5、渲染混合视图
src/core/instace/index.js执行完后,会继续执行下一个文件
导出函数initGlobalAPI(视图:GlobalAPI)>
//配置
const configDef={}
configDef.get=()=config
if (process.env.NODE_ENV!=="生产")
configDef.set=()构造函数
警告(
不要替换视图。配置对象,而应设置个别字段。
)
}
}
//新增了一个配置(配置)属性
Object.defineProperty(视图、配置、配置定义)
//新增了一个静态成员东尼
vue。util=>
警告,
延伸,
合并选项,
设置为活动
}
//新增了3个静态成员设置删除下一滴答
视图。集合=集合
vue。删除=删除
vue。nexttick=nexttick
//新增了一个静态成员观察到的
观察到的视图=t(obj:t):t=& gt;
请注意(obj)
返回对象(返回对象)
}
//初始化了选项包括此时选项包括是空对象/T
vue。选项=对象。创建(空值)
ASSET_TYPES.forEach(类型=>
查看。选项[类型]=对象。创建(空)
})
视图。选项. base=视图
//注册了一个全局组件保持加电组件内部就是保持活力的组件导出
延伸(查看。选项。组件,内置组件)
//下面是分别初始化了查看。使用()视图。mixin()视图。扩展()
initUse视图
initMixin视图
initExtend视图
//初始化vue。指令()、vue。组件()、vue。过滤器()
initassetregisters视图
}
1.2、src/core/index.js
可以看出,这个文件,主要是给视图(视图)新增了很多静态实例方法和属性,具体新增了哪些,
我们继续看被执行的那个方法initGlobalAPI(Vue)美元
initGlobalAPI视图
导出函数initGlobalAPI(视图:GlobalAPI)>
//配置
const configDef={}
configDef.get=()=config
if (process.env.NODE_ENV!=="生产")
configDef.set=()构造函数
警告(
不要替换视图。配置对象,而应设置个别字段。
)
}
}
//新增了一个配置(配置)属性
Object.defineProperty(视图、配置、配置定义)
//新增了一个静态成员东尼
vue。util=>
警告,
延伸,
合并选项,
设置为活动
}
//新增了3个静态成员设置删除下一滴答
视图。集合=集合
vue。删除=删除
vue。nexttick=nexttick
//新增了一个静态成员观察到的
观察到的视图=t(obj:t):t=& gt;
请注意(obj)
返回对象(返回对象)
}
//初始化了选项包括此时选项包括是空对象/T
vue。选项=对象。创建(空值)
ASSET_TYPES.forEach(类型=>
查看。选项[类型]=对象。创建(空)
})
视图。选项. base=视图
//注册了一个全局组件保持加电组件内部就是保持活力的组件导出
延伸(查看。选项。组件,内置组件)
//下面是分别初始化了查看。使用()视图。mixin()视图。扩展()
initUse视图
initMixin视图
initExtend视图
//初始化vue。指令()、vue。组件()、vue。过滤器()
initassetregisters视图
}
1.3、src/platforms/web/runtime/index.js
1.4、src/platforms/web/entry-runtime-with-compiler.js
此文件,最主要的作用就重写了视图(视图)原型下的$mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount方法。具体$mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount(安装代号)$ mount方法中做了些什么,我们后面会讲
1.5、vue初始化总结
上面写的整个过程,都是用户在使用视图(视图)时,引入视图(视图)文件后,立刻会执行的一些东西
这些执行完后,是不是会继续去执行我们项目中的手,js文件啊,
此时会执行到
新建视图[
路由器,
商店里,
渲染:h=h(应用程序)
}。$ mount(# app)
这个时候,会开始调用,我们的视图(视图)构造函数
2、vue构造函数执行
此时,会先执行视图(视图)构造函数,
可以看出,主要执行_init方法。从这里开始,vue的生命周期开始执行。
它只是above _init()方法中最重要的一部分代码。(代码太多,就不全截图了。自己看源代码)。可以看出:
2.1、beforeCreate钩子
在生命周期beforeCreate hook之前,vue的主要任务是给vue原型添加各种属性和方法,给vue添加静态属性和方法,给vm实例添加属性和方法。
2.2、created钩子
从上图可以看出,在执行beforeCreate钩子之后,执行了三个主要的方法:init injections、init state和init provide。
//注入注入到虚拟机实例中
callHook(虚拟机,“创建前”)
//注入注入到虚拟机实例中
初始注入
//初始化虚拟机的$ props,$ methods,$ data,computed,watch
初始化状态(虚拟机)
//将提供注入虚拟机实例
初始化提供(虚拟机)
//执行创建的生命周期
callHook(虚拟机,“已创建”)
其实重点是在initState(vm)方法上,其中$ props,$ data,$ methods,computed,watch等。初始化虚拟机实例的。同时在其中调用一个initData()方法,在这个方法中调用observer()方法,将数据中的所有数据转换成响应数据。也就是说,添加一个数据拦截器。
因此,可以看出,在创建生命周期之前,vm的$ props、$ data、$ methods、computed和watch属性将被初始化。
因此,这就是为什么我们可以调用我们的数据中的各种数据和下面的方法如props或methods in created。
创造的生命周期结束后,继续往下看。
可以看出,这里判断的是vm是否。$options.el是否存在以及是什么vm。$options.el是。
new Vue({})时,传入的对象的所有属性都将挂载在options下,
新Vue({
埃尔: #app
路由器,
店,
render: h=h(App)
})
所以,vm。$options.el是上面传入的el。
在这里,判断el是否存在,如果存在,进行到$mount。
那大家可能就好奇了。如果不存在,是不是卡住了?没有人会掉队。是的,如果不这样,就不会继续下去。如果代码继续往下走,就必须执行$mount方法。
至此,我们再来看看vue一直被普遍使用的情况。
新Vue({
路由器,
店,
render: h=h(App)
}).$ mount(“# app”)
这里没有介绍el,所以
我肯定不会走的。但是,当用户在新的vue中时,他们可以使用新的Vue实例调用$mount。这样的话,如果看官网的生命周期图,可能更容易理解。
好了,我们继续。下一步是执行$mount。让我们看看$mount方法。
2.3、$mount函数
我们之前初始化的时候,重写了$mount,记得吗?所以,当我们此时执行$mount时,我们执行的是重写后的mount。
这里存储重写前的挂载方法,然后在最后调用重写前的挂载方法。
重写后,最关键的代码是确定是否有渲染函数。
该步骤的主要功能是确定是否存在渲染功能,
如果是,在重写之前,在执行$mount方法之前直接渲染render函数,
如果没有,则在会前判断是否有模板template template是否存在,options.template可能是id选择器或dom)。如果有模板,则获取模板中的内容并赋给模板。如果options.template不存在,将直接使用el指定的dom作为模板(即#app)获取el下的dom并赋给模板。
将模板获取到dom后,继续向下,将这个模板编译成一个渲染函数,并将编译后的渲染函数挂载到options.render属性下。
然后我们会在重写之前继续执行$mount。理解了这一点,我们就可以理解生命周期图的另一部分了。
2.4、beforeMount
接下来,让我们继续看看重写之前$mount函数的执行情况
可以看出,在\ $mount中,主要执行函数mountComponent。让我们继续看看mountComponent函数。
可以看出,这个函数主要做了以下四件事。
我们一个一个来看。
1.beforeMount钩子是执行的,所以可以得出结论,在beforeMount之前,我们主要是初始化和获取render函数。beforeMount之后,render函数渲染成虚拟dom,然后更新真实domrender函数得到的途径有3种。
首先,用户自己传递渲染。
第二:的。vue文件被编译成render。
就这样,我传入了一个render函数,App.vue文件是在函数中使用H函数之前执行的。
的最终转换。vue文件到渲染函数需要vue-loader的帮助。
第三,将模板编译成渲染函数。
2.定义了一个updateComponent函数,其中调用了vm的_update方法,vm。_render()方法,它将执行
将行作为参数传递给_update方法后的结果。_render方法我们前面说过,他在内部将render函数渲染到一个虚拟dom中,所以_render()的返回值是一个vnode。
我们先来看看_render()函数是如何将渲染函数转换成虚拟dom的。
然后我们来看看_update函数内部做了什么。
可以看到,在_update函数中,执行了__patch__方法来比较新旧两个dom,从而找出差异,更新真实的dom。如果是第一次渲染,当前的vnode会直接生成到真正的dom中。
所以得出结论,整个updateComponent方法的主要功能是渲染渲染函数,更新dom。
而何时更新dom的关键是何时调用updateComponent函数。
3.新建观察器实例
可以看到,当watcher实例是新的时,updateComponent函数作为参数传入。
此时,当我们查看新的观察器时,观察器构造函数将被执行。让我们看看在观察器构造函数中做了什么。
有三种观察器:观察器渲染、观察器函数观察器和计算观察器。我们在这里将页面呈现给呈现观察者。
我们上面传入的函数被传递给了getter。
继续调用get()
可以看到我们传入的函数是在get()中调用的,我们传入的函数是render函数,它触发虚拟dom更新真实dom,返回的值是渲染后的真实dom,最后赋给this.value,this.value最后会用来更新依赖者。而我们目前的watcher实例是主vue实例的watcher,所以可以理解为整个页面的watcher。当我们称之为。$fouceUpdate(),我们调用这个实例的Update方法来更新整个页面。
所以使用new Wacher时会自动调用一次updateComponent,这是我们第一次渲染。
至此,我们继续往下看。
在内部,判断vm是否。_isMounted为true(即挂载的钩子已经执行)和VM。_ ismounted是fase(即当前组件没有被销毁)。此时,如果生成了更新,则意味着这不是第一次渲染。然后,如果beforeUpdate钩子被执行,那么updated一定会被跟随。我们这里就不谈更新了。
在新的观察者之后,代码继续下降。
判断如果当前vnode为null,说明之前没有生成过虚拟dom,也就是说这肯定是第一次渲染。至此,vm。_isMounted设置为true。并执行安装的挂钩功能。至此,第一次渲染完成。
2.5、mounted
可以看出,从beforeMount到mounted的整个过程中,主要工作是
1.将render函数渲染成虚拟dom vnode。
2.执行虚拟机。_update函数将虚拟dom转换为真实dom。
如果是在beforeUpdate和updated hook之间,说明不是第一次渲染,那么会有新旧虚拟dom。这时,vm的功能。_update就是对比新旧vnode,得出差异,更新需要更新的内容。
这是第一次渲染的全过程。关于vue第一次渲染的全过程这篇文章就说到这里。更多相关vue首渲染内容,请搜索我们之前的文章或者继续浏览下面的相关文章。希望大家以后能多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。