虚拟dom && diff算法
虚拟dom是什么?
它是一个Object对象模型,用来模拟真实dom节点的结构
虚拟dom的使用基本流程
获取数据( ajax fetch )
var data = {
id: 1,
name: 'XXXX'
}
创建vdom
<div class = "box">
<ul>
<li> {{ data.name }} </li>
</ul>
</div>
通过render函数解析jsx,将其转换成 vdom结构
var vdom = {
tag: 'div',
attr: {
className: 'box'
},
content: [
{
tag: 'ul',
content: [
{
tag: 'li',
content: data.name
}
]
}
]
}
将vdom渲染成真实dom(render函数)
数据更改
data.name = 'ZZZZ'
vdom = {
tag: 'div',
attr: {
className: 'box'
},
content: [
{
tag: 'ul',
content: [
{
tag: 'li',
content: data.name
}
]
}
]
}
使用diff算法比对两次vdom,生成patch对象
根据key将patch对象渲染到页面中改变的结构上,而其他没有改变的地方是不做任何修改的( 虚拟dom的惰性原则 )
什么是jsx?
- jsx javascript + xml
diff算法是什么?
diff算法是比较两个文件的差异,并将两个文件不同之处,将这个不同之处生成一个补丁对象(patch)
diff算法来源后端
前端将其应用于虚拟dom的diff算法
vue中将 虚拟dom的diff算法放在了 patch.js文件中
使用js来进行两个对象的比较( vdom 对象模型)
diff算法是同级比较
给每一个层级打一个标记,这个标记是一个数字( 这个数字就是 key )
注意: vue是一是MVVM框架,Vue高性能的原因之一就是vdom
验证 key
- 列表循环一定加key
- key最好是使用具有唯一标识性的 id
为什么列表循环要加key ?
- 在Vue中,存在一个DOM复用机制,会尽量的回收DOM元素进行复用,而这个机制本身是高效的,但很多时候也会造成不可预知的Bug,而在加了key值后,元素就有了一个标识,复用机制不会复用带key值的元素。而React也存在类似的机制。
- 反之,若使用相同的key值,可以使组件复用,也有可能导致渲染内容缺失。
- 因此,key值一般来说,最好是
独一无二
的。 - 除此之外,虚拟DOM在使用Diff算法进行对比时,若存在key值,可以更高效更迅速。
Vue有两大特性
指令 – 用来操作dom
组件 – 组件是html css js 等的一个聚合体
为什么要使用组件?
- 组件化
- 将一个具备完整功能的项目的一部分进行多处使用
- 加快项目的进度
- 可以进行项目的复用
- 要想实现组件化,那么我们使用的这一部分就必须是完整的,我们把这个完整的整体就称之为组件
- 插件: index.html img css js
- 如果能将 html css js img 等多个部分放在一起,那该有多好,vue将这个聚合体的文件称之为,单文件组件( xx.vue )
基础的组件创建
-
全局注册
var Hello = Vue.extend({ template: '<div> 这里是father组件 </div>' }) //VueComponent( option ) Vue.component( 'Father', Hello ) new Vue({ el: '#app' })
-
局部注册
var Hello = Vue.extend({ template: '<div> 这里是XXXX </div>' }) new Vue({ el: '#app', components: { // key: value key是组件名称 value是组件配置项 // 'val': Hello, 'val': Hello } }) new Vue({ el: '#root' })
-
组件的嵌套
/* 组件的嵌套 父组件里面放子组件 ----》 类似于dom结构的父子级结构 将子组件以标签的形式放在父组件的模板中使用 切记,不要放在父组件的内容中 组件不仅可以用双标签表示,也可以使用单标签表示 */ new Vue({ el: '#app', components: { 'Father': { template: '<div> father组件 <Son /></div>', components: { 'Son': { template: '<div> son组件 </div>' } } } } })
关于组件
-
vue是如何扩展组件的?
extends方法 https://cn.vuejs.org/v2/api/#extends
-
vue为什么要以标签的形式使用组件
Vue不进行 实例化 Vue.extend(),vue借鉴了react,react中组件是以标签的形式使用的.
-
组件使用为何要注册
为了符合 html / html5的规则,所以组件的标签化使用必须注册
组件的一些特殊使用规则 【 is 规则】
/*
is规则
ul>li ol>li table>tr>td select>option
如上直属父子级如果直接组件以标签化形式使用,那么就会出现bug
解决: 使用is规则: 通过is属性来绑定一个组件
<tr is = "Hello"></tr>
案例: table
*/
<div id="app">
<table>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr is = "Hello"></tr>
</table>
</div>
---------------------------------------javascript-------------------------------------
Vue.component('Hello',{
template: '<tr> <td> 4 </td> <td> 2 </td><td> 3 </td></tr>'
})
new Vue({
el: '#app'
})
组件的template
/*
template使用:
1. 实例范围内使用
template中的内容被当做一个整体了,并且template标签是不会解析到html结构中的
2. 实例范围外使用
实例范围外template标签是不会被直接解析的
组件要想使用template使用,我们采用第二种
但是使用第二种template使用后,有个弊端,template标签结构会在html文件中显示
解决: 使用webpack、gulp等工具编译,将来要用vue提供的单文件组件
*/
--------------------------------------------------------------------------------------
<div id="app">
<h3> 实例范围内使用 </h3>
<template>
<div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</template>
<h3> 使用 hello 组件</h3>
<Hello></Hello>
</div>
<h3> 实例范围外使用 </h3>
<template id="hello">
<div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
</template>
---------------------------------------javascript-------------------------------------
Vue.component('Hello',{
template: '#hello'
})
new Vue({
el: '#app'
})