数据驱动视图(MVVM)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fjw747sj-1621928755946)(C:\Users\飞牛牛\AppData\Roaming\Typora\typora-user-images\image-20210519135404701.png)]
MVVM:区别与传统组件,传统组件传入的是静态数据,每次修改数据都需要操作DOM.而MVVM是通过数据驱动视图,只需要修改model(data)里面的数据就可以动态的渲染到DOM上面,不需要操作DOM 。
Vue响应式
Vue如何实现响应式
通过核心API Object.defineProperty
Object.defineProperty(data,"name",{
get:function(){
console.log("get")
return name
},
set:function(newV){
name=newl
}
});
每当获取name 属性的时候就会触发get函数获取值,当修改数据 的时候就会触发set函数
Object.defineProperty缺点
深度监听,需要递归到底,一次性计算量大。
无法监听新增属性/删除属性需要通过Vue.set和Vue.delete方法
无法监听原生数组,需要特殊处理
虚拟DOM和diff算法
vdom是实现vue和react的重要基石
vdom:用JS模拟DOM 结构,计算出最小的变更,操作DOM
为什么需要用到vdom?
传统的页面开发需要不断的给节点添加事件,然后回调中实现更新dom节点。大量的操作dom节点会导致非常消耗性能,这样就会导致程序变得非常难以维护。而VDOM就是为了避免大量操作DOM而产生的,通过js模拟dom结构。然后用diff算法计算出最小的变更,这样就会使得实际操作DOM次数大大减少,性能得到较大提升
基于数据驱动视图方式,有效控制dom操作提升性能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yg3eWG8t-1621928755948)(C:\Users\飞牛牛\AppData\Roaming\Typora\typora-user-images\image-20210519164604415.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YDTBtIIg-1621928755950)(C:\Users\飞牛牛\AppData\Roaming\Typora\typora-user-images\image-20210519164615411.png)]
diff算法
diff算法是vdom最核心、最关键的部分
diff算法就是对比,将dom结构与JS模拟的dom结构进行对比,计算出最小的变更范围。
-
只比较同一阶级,不跨越比较
-
tag不同,则直接删掉重建,不再深度比较
-
tag和key,两者都相同,则认为是相同节点,不再深度比较
diff算法可以最大程度的减少dom渲染的一个范围
diff算法核心概念
h函数:生成模拟的dom节点,返回一个vnode对象
init方法:返回一个patch函数
patch函数:实现dom相关的更新,把不同的虚拟DOM渲染到真实的DOM上去
-
如果一个参数不是vnode,则创建一个空的vnode,关联到这个dom元素
-
如果两个vnode的key和sel相同,调用patchVnode方法更新新节点
-
如果两个vnode不相等,则删除节点重建
使用createElm方法将vnode转换成真正的dom元素
使用removeVnodes方法删除真正的DOM节点
diff:我们怎么样知道oldVnode和newVnode之间的不同。
key属性的使用
给每一个数据项创建一个唯一的标识,利于高效的数据更新,最大限度的利用已有的数据。减少渲染次数,提升渲染性能
例如:
在数组中 如果没有使用key属性,在给数据重新排序后,会先销毁数组然后重新渲染新的数组。如果使用了key属性只会将已有的数据进行移动即可。例如在ABD插入C的时候没有key属性会将D更新成C然后插入D。在有key的时候会直接在BD之间插入C。
模板编译
模板编译就是将模板转换成JS代码,也就是说的render函数,执行render函数返回vnode
使用webpack vue-loader,会在开发环境下编译模板。
JS里面的with语法:
- 改变{}内自由变量的查找规则,当作obj属性查找
- 如果找不到obj的属性会报错
v-model双向绑定的原理:
在组件执行的时候会先将模板转换为js代码,在实现双向绑定的时候, 在domProps里面会生成一个input事件,并且将$event.target.value赋给this.name以及会将输入框的value=this.name。所以能够实现双向绑定
组件渲染和更新过程
初次渲染:
- 解释模板为render函数(或在开发环境已完成)
- 触发响应式,监听data属性getter setter
- 执行render函数,生成vnode,patch(elem,vnode)
更新过程:
- 修改data,触发setter(此前数据在getter中已被监听)
- 重新执行render函数,生成newVnode
- patch(vnode,newVnode)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HXJ5bzeC-1621928755952)(C:\Users\飞牛牛\AppData\Roaming\Typora\typora-user-images\image-20210521142145109.png)]
异步渲染
页面渲染是异步的,$nextTick是异步渲染,会等待dom节点渲染完后再回调
页面渲染时会将data的修改做整合,多次data修改 也只会渲染一次
- 汇总data的修改,一次性更新视图
修改一次data就渲染一次页面会导致浏览器性能不断重排,性能消耗大
- 减少DOM操作次数,提升性能
前端路由原理
hash模式:
- hash变化会触发网页跳转,既浏览器的前进、后退
- hash变化不会刷新页面
- hash永远不会提交到Server端
history模式:
- 用url规范的路由,但跳转时不会刷新页面
- history.pushState
当一次访问页面的时候会刷新页面,但是跳转页面的时候保证不会刷新页面。通过history.pushState方法跳转到不同的页面(路由)
- window.onpopstate
使用window.onpopstate方法监听浏览器前进和后退
为什么组件中的data必须是一个函数?
答:
2.1)因为如果data是一个对象,对象是引用类型,那复用的所有组件实例都会共享这些数据,就会导致修改一个组件实例上的数据,其他复用该组件的实例上对应的数据也会被修改。
2.2)如果data是一个函数,函数虽然也是引用类型,但是函数是有作用域的,函数内的变量不能被外部访问到,这样每个组件实例都会有个独立的拷贝同时又因为函数作用域的限制修改自己的数据时其他组件实例的数据是不会受到影响的
总结:
对象是引用类型,且没有作用域,会导致一改全改;
函数是引用类型,但它有作用域,不会彼此受牵连。
如何抽离公共逻辑
使用mixin可以抽离公共的逻辑
再先mixins.js里面写好一些公共的逻辑,然后在组件里复用就行了
缺点:
- 遍历来源不明确,不利于阅读。
- 多mixin可能会造成命名冲突。
- mixin和组件可能出现多对多的关系,复杂度较高,做好只用1个吧
什么是异步组件
使用场景:加载大组件的时候、路由异步加载时候
异步组件是 vue 的一种性能优化的方法,比如可以运用在首屏加载等等场景。
异步组件就是组件通过 import() 函数引入,什么时候需要什么时候才加载
<template>
<div>
<Button @click="show = true">显示Form</Button>
<FormCom v-if="show"/>
</div>
</template>
<script>
export default {
components: {
FormCom: () => import('./FormCom')
},
data() {
return {
show: false
}
}
}
</script>
<!-- 子组件 -->
<template>
<input type="text" :value="value">
</template>
<script>
export default {
data() {
return {
value: ''
}
}
}
</script>
什么时候需要beforeDestory
- 解除自定义事件event.$off
- 清除定时器
- 解绑自定义的DOM事件
这些都是为了防止内存泄漏
vue常用的性能优化
- 合理使用v-show和v-if
- 合理使用computed
- v-for时加key,以及避免和v-if同时使用
- 自定义事件、dom事件、定时器及时销毁
- 合理使用异步组件
- 合理使用keep-live
- data层级不要太深
件event.$off**
- 清除定时器
- 解绑自定义的DOM事件
这些都是为了防止内存泄漏
vue常用的性能优化
- 合理使用v-show和v-if
- 合理使用computed
- v-for时加key,以及避免和v-if同时使用
- 自定义事件、dom事件、定时器及时销毁
- 合理使用异步组件
- 合理使用keep-live
- data层级不要太深