注入
把配置项里的一些成员放到vue实例里,这个过程叫注入。
这个过程是在Vue()构造函数里完成的。
通过new Vue({})创建了一个vue实例对象,这个实例对象里本身自带了一写成员,是vue框架给我们加的一些成员。
vue实例里的成员分成三部分:
- $开头(一些实用方法和属性,便于开发者使用)
- 下划线_开头 (vue内部使用的成员,不建议开发者使用)
- 从配置项中注入的成员
为什么vue自带的成员要用$或者_开头? 防止与注入的成员重名。
vue模版可以直接使用vue实例中的成员。
为什么能直接使用{{title}},因为vue实例里有title。
数据响应式:数据改变,模版重新渲染。 数据响应的过程是在注入之后才执行的。
虚拟DOM树
虚拟DOM是一个普通的js对象。用于描述界面上应该有什么。(此时页面上还没有)
举例:
var vnode = {
tag: "h1",
children: [
{
tag: undefined,
text: "这是第一个vue应用",
},
],
};
// 该对象描述了:有一个标签名为h1的节点,里面有一个子节点,子节点是一个文本节点,文本内容为‘这是第一个vue应用’
在vue模版里,这些都不是真正的dom元素,vue会把它当成字符串,会把它当成虚拟DOM。
假如直接操作真实的dom元素,就会严重的影响效率,因为真实的dom元素会触发浏览器的重排、回流,会触发重新渲染。
所以,为了提高效率,vue使用了虚拟DOM(vnode)的方式来描述要渲染的内容。
vue模版并不是真实的DOM,它会被编译为虚拟DOM
举例说明把vue模版编译为虚拟DOM的样子:
<div id="app">
<h1>第一个vue应用:{{title}}</h1>
<p>作者:{{author}}</p>
</div>
var vnode = {
tag:'div',
children:[
{
tag:'h1',
children:[
{
text:'第一个vue应用:Hello World'
}
]
},
{
tag:'p',
children:[
{
text:'作者:袁'
}
]
}
]
}
虚拟DOM树最终会生成真实的DOM树。
先生成虚拟DOM,再生成真实的节点。
当数据变化时,重新渲染页面,这个过程是怎样的? 当数据变化后,重新生成新的vnode tree(虚拟DOM),vue会比较新旧两棵vnode tree(虚拟DOM树),找出差异,然后仅把差异应用到真实DOM tree中。
举例说明:
把author改成‘进’,然后重新生成虚拟DOM,比较发现只有text有差异,然后仅把text应用到真实dom中。
可见,在vue中,要得到最终界面,必须要生成vnode tree,vue通过以下逻辑生成vnode tree:
虚拟DOM如何来的?
- 是运行render函数的返回结果
render(){},这个函数返回的结果就是它的虚拟DOM树。 举例:
<div id="app"></div>
const vm = new Vue({
el:'#app',
data:{
title:'Hello World',
author:'袁'
},
render(h){
return h('div',[
h('h1',`第一个vue应用:${this.title}`),
h('p',`作者:${this.author}`)
])
}
})
但是,直接使用render函数生成节点很麻烦,所以,vue给我们提供了模版,即<div id="app">xxx</div>,模版的作用只有一个,就是根据模版,生成render函数。也就是说,假如不写render函数,只写模版,vue会把模版编译成render函数,最终还是render。
具体逻辑如下:
- 先看render,有render就执行render,不看其他的;
- 如果没有render,则看template,有template,则把它编译成render;
- 如果没有template,则看el对应的元素,把它作为模版。把el元素的outerHTML作为模版。
总之,一定得有render,因为只有render能生成虚拟DOM,虚拟DOM才能渲染出真实DOM。
注意:虚拟节点必须是单根的。
挂载
将生成的真实的DOM树,放置到某个元素位置,称之为挂载。
挂载的两种方式:
- 通过
el:'css选择器'进行挂载 - 通过
vue实例.$mount("css选择器")进行挂载
完整流程
- 创建vue实例
- 把成员注入到实例里(注入完成后,有了数据响应式)
- 编译生成虚拟dom树
- 如何编译?
- 先看render
- 无render则编译template,把它生成redner,再运行render
- 无template则编译模版,把它生成redner,再运行render
- 如何编译?
- 根据虚拟DOM树生成真实DOM树,生成完之后进行挂载5. 此时首次渲染完成
- 数据变化,会重新渲染
- 如何重新渲染?
- 重新生成新的虚拟DOM树,即重新调用render
- 对比新旧虚拟DOM树的差异
- 将差异应用到真实DOM树中
- 如何重新渲染?
- 此时二次渲染完成