前言
小编所分享整理的备战系列文章里面不会是一个完全完整且系统的一个内容,主要是针对所描述的相关知识自己觉得的重点,所以有时候可能整体文章逻辑上会不是很好,文章整理就压缩了一下,但还是会用心滴。以下很多东西涉及到Vue源码,小编还是简单描述一下,整理源码到文章太麻烦也不方便查看。
MVC、MVVM架构模式
说到Vue那么最开始我想说到的一个点就是他俩,用了这么久的Vue那么应该要知道他是MVVM软件架构设计模式。
MVC
从前端到后端交互,前端请求通过路由找到对应控制器拿到数据,数据交替是单向的。简单来讲就是前端负责页面后端负责数据。
MVVM
细化了MVC的前端部分,数据直接挂到框架上面直接渲染更新。前端数据需求量的增加使其成为了一个必然的趋势,MVVM可以说是MVC前端部分的一个抽离。
Vue中模板的编译原理
编译原理
我们先从Vue是怎么从一个个组件变成了一个页面来说,怎么从组件代码变成了一个render函数,我们先说三大步
- 将模板转换成ast树(虚拟DOM对象,vnode树),主要是正则实现解析代码然后在提取相关数据放入对象树中
- 优化树
- 将ast树生成js代码
渲染及更新
我们从组件如何渲染到真实DOM
-
通过
CreateElement
方法将我们的组件对象生成虚拟DOM对象 -
拿到虚拟DOM,Vue通过
vue.extend()
方法构建子組件的枸造凾数,到这里我们虚拟DOM操作就结束了接下来是实例化 -
updata
方法执行,我们先执行CreateComponent
方法去new一个我们传过来的虚拟DOM对象,实例化后Vue就会给这个组件以内部watcher去渲染,整个粗略的就是这样的一个渲染过程
那么更新内部就是依赖于patchvnode流程核心diff算法去做比较然后更新界面。
Vue采用异步渲染
既然上面提及到了渲染那么这边说一下异步渲染,Vue是组件级别更新。为啥异步打个很简单的比方
this.a = 1
this.b =2
我们上面所改变的两个值对应同一watcher的话按照同步流程那我们就得更新两次了。
那么我们的实际流程是刷新界面数据改变的时候回通知notify
方法进行更新视图,然后我们会将对应watcher附一个id标记存到一个队列之中,这样我们就可以清除掉相同的watcher
只保留最新的,然后渲染页面,最后通过nextTick
方法异步清空这个存放watcher的队列然后进行下一个组件渲染。
响应式数据原理
这一部分小编认为是Vue最核心的部分也叫做数据双向绑定原理,稍微概述一下:
核心方法就是Object.defineProperty()
,通过他给data里面属性重新定义一下,当页面取到相关属性时Vue内部会查看他的watcher,也就是之前所收集的依赖内容,然后通知响应更新。具体有几步
- 初始化用户传入的数据initData
- 对数据进行观测
- 进行对象处理
- Object.defineProperty的get、set方法时间检测,set方法收集数据对象的watcher、get方法内部做一个判定如果数据改变则更新响应视图(通过notify方法)
但是最新发布的Vue.3上好像是已经用到了Proxy去实现。
Vue生命周期
生命周期概述
-
beforeCreate
在实例初始化之后,beforeCreate 的钩子函数中就不能获取到 props、data 中定义的值,也不能调用 methods 中定义的函数。 -
created
实例已经创建完成之后被调用。前面两个的钩子函数执行的时候,并没有渲染 DOM,所以我们也不能够访问 DOM,一般来说,如果组件在加载的时候需要和后端有交互,放在这俩个钩子函数执行都可以,如果是需要访问 props、data 等数据的话,就需要使用 created 钩子函数 -
beforeMount
在挂载开始之前被调用:vm._render()函数首次被调用。 -
mounted
el 被新创建的vm.Se1替换,并挂载到实例上去之后调用该钩子。 -
beforeUpdate
数据更新时调用,发生在虚拟DOM重新渲染和打补丁之前。 -
updated
由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 -
beforeDestroy
实例销毁之前调用。在这一步,实例仍然完全可用。 -
destroyed
Vue 实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务 器端渲染期间不被调用。
常用的生命周期能做什么事情
-
created实例已经创建完成,因为它是最早触发的原因可以进行一些数据 ,资源的请求。
-
mounted实例已经挂载完成,可以进行一些DOM操作
-
beforeUpdate可以在这个钩子中进一步地更改状态 ,这不会触发附加的重渲染过程。
-
updated可以执行依赖于DOM的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能 会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
-
destroyed可以执行一些优化操作,清空定时器 ,解除绑定事件
Vuex
Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。
Vue常见问题
Vue中如何检测数组变化?
使用函数劫持的方式,Vue内部重写了数组的方法,Vue将data中的数组操作时指向自己的数组原型方法,重写的方法里面就通知对依赖的更新。
Vue中Computed(计算属性)的特点
从两个问题出发:
建立与其他属性(如:data、 Store)的联系; 属性改变后,通知计算属性重新计算。
实现时,主要如下
-
初始化 data, 使用
Object.defineProperty
把这些属性全部转为 getter/setter。 -
初始化
computed
, 遍历 computed 里的每个属性,每个 computed 属性都是一个 -
watch实例。每个属性提供的函数作为属性的
getter
,使用 Object.defineProperty 转化。 -
Object.defineProperty getter依赖收集。用于依赖发生变化时,触发属性重新计算。
-
若出现当前 computed 计算属性嵌套其他computed计算属性时,先进行其他的依赖收集。
计算属性与watcher的区别,计算属性是有缓存的。计算属性本质上是 computed watcher,而侦听属性本质上是 user watcher。就应用场景而言,计算属性适合用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
Vue中v-if和v-show的区别
v-if如果条件不成立不会渲染当前当前指令所在的节点的DOM元素 v-show值切换当前DOM显示或者隐藏(display属性的改变)。
说到这个点这里提及一下v-if和v-for不能连用,因为v-for优先级大于v-if,然后我们可以在外层加一个去判定v-if就ok了
v-for为啥要用key
不用key值的话是数组会复用空间,那么修改数组对象时会产生问题。
data为啥要是一个方法
很简单的一个理解当data是一个对象时我们内部去创建组件实例的时候调用data那么这个data对象会在原型上,后续在创建就是与之前用的是一个data对象值,避免组件间的数据互相影响,用方法每一次new一个实例组件那么会返回一个新的data对象去供其调用。
Vue组件如何通信
父到子通过props通过属性传递、子到父emit,父亲传给儿子一个方法,让儿子去调用(简易的发布订阅)。