Vue渲染过程分析
Vue建议在大多数情况下使用模板来创建你的HTML。但毕竟模板是模板,不是真正的dom节点。从模板到真实dom节点还有一些步骤
将模板编译成渲染函数实例并挂载它。根据根节点render函数的调用,递归生成一个虚拟dom,与虚拟dom进行比较。当真实dom组件中的数据发生变化时,组件和子组件将数据作为道具再次调用渲染函数,生成虚拟dom,并返回步骤3,步骤3360,模板进行渲染。
当我们使用Vue的组件化来开发应用程序时,如果我们仔细查看我们想要介绍的组件,示例如下
//app . vuetemplate div hello word/div/templatescriptordefault { }/script style/style在我们的主入口main.js
从“vue”导入Vue从“App”导入。/App ' console . log(App)new Vue({ render :h=h(App)})。$ mount(' # app ')
我们可以看到我们介绍的App的模块里面有一个对象,对象里面有一个叫做render的方法。在谈论渲染函数之前,我们可以考虑一下,一次加载一个组件,解析模板,解析后生成Dom,并将其挂载到页面上。这会导致效率低下。在使用Vue-cli进行组件开发时,在我们介绍组件之后,实际上会有一个解析器(vue-loader)来解析这个模板并生成render函数。当然,如果解析器没有将它解析为呈现函数,这并不重要。第一次挂载组件时,Vue会自己解析。源代码请参考: https://github.com/vuejs/vue/blob/dev/src/platforms/web/entry-runtime-with-compiler . js。
通过这种方式,可以保证每次组件调用渲染函数时,VNode都是通过使用渲染函数生成的。
步骤2:虚拟节点虚拟节点
当我们将Vue的实例挂载到#app时,我们将调用实例中的render方法来生成虚拟DOM。让我们看看什么是虚拟节点,并修改示例。
new Vue({ render :h={ let root=h(App)console . log(' root : ',root) return root }})。$ mount(' # app ')
上面生成的VNode是一个虚拟节点,虚拟节点中有一个属性elm,指向真实的DOM节点。因为VNode指向真实的DOM节点,所以生成的DOM节点可以在比较虚拟节点后直接替换。
这样做有什么好处?
如果内部数据发生变化,组件对象将触发渲染功能并重新生成虚拟节点。然后可以直接找到对应的节点,直接替换。那么这个过程只会发生在这个组件中,不会影响其他组件。因此,组件与组件是隔离的。示例如下:
//main . jsconst root=new Vue({ data : { state : true },mounted(){ setTimeout(()={ console . log(this)this . state=false },1000) },render 3360 function(h){ const { state }=this//状态更改触发render let root=h(app)console . log(' root 3360 ',root) return root }})。$ mount(' # app ')//app . vuescriptorexport default { render :(h)={ let app=h(' h1 ',[' hello world '])console . log(' app : ',app)return app } }/script
我们可以看到,当在main.js中重新触发render函数时,在render方法中引用了子组件App.vue。但是它没有触发App.vue组件的渲染功能。
在组件中,什么会触发渲染?
如何触发组件的渲染
数据劫持是Vue的一大特色,原则官也讲了很多深度响应原则。当我们给组件(集合)的数据属性赋值时,如果这个属性在组件内部的第一次渲染过程中被引用(数据的属性被访问,也就是数据劫持的get),它包括生命周期方法或者渲染方法。组件的更新(在更新-渲染-更新之前)将被触发。
注:为防止数据被多次设置并触发多次更新,Vue将更新存储在异步队列中。通过这种方式,可以保证多组数据只触发一次更新。当道具触发组件的重渲染时是如何发生的?
当父组件的数据通过props传递给子组件时,子组件在第一次呈现时具有在其生命周期中调用数据相关的props或render方法的属性,这样子组件也被添加到父组件的数据相关属性依赖中,这样在设置父组件的数据时,就相当于触发了自身和子组件的更新。
示例如下:
//main . vueimport Vue from ' Vue ' import App from '。/App ' const root=new Vue({ data : { state : false },Mounted () {settimeout ()={this。state=true},1000)},render : function(h){ const { state }=this//状态更改触发render let root=h(App,{ prop : { status 3360 } state } })console . log(' root : ',root) return root }})。$ mount(' # app ')window . root=root//app . vuescriptorexport default { prop : { status 3360 Boolean },The render : function(h){ const { status }=this let app=h(' h1 ',[' hello world '])console . log(' app 3360 ',app)return app } }/脚本截图如下:
在main.js中,状态会改变,false=true会触发自身及其子组件的呈现方法。
补充
以上内容是我的一些体会。由于水平有限,内容中存在一些错误或表达不当。欢迎大神指导我们!
PS:VUE渲染过程中{{xxx}}显示的解决方案
这是由浏览器的呈现机制造成的。如果您的js引用在底部,浏览器将首先加载dom。此时,您用于呈现的{{}}标识符将被解析为字符串并显示在页面上,因为您尚未读取与该标识符对应的js文件。我们可以用自定义属性v斗篷来解决。
将v-斗篷:添加到对应于实例对象的标签中
Div id=“包装”v-斗篷,然后在css中定义属性选择器
[v-斗篷]{ display : none } v-斗篷将在创建vue实例时被移除,而在未创建实例对象时,此标记中的内容将被隐藏。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。