vue|Vue面试常用详细总结


文章目录

    • 一、 Vue生命周期
    • 二、vue响应式原理
      • Vue2.0
      • Vue3.0
    • 二·0、观察者模式
    • 三、计算属性computed
    • 四、侦听属性watch
    • 五、computed 和 watch 区别
    • 六、v-show 与 v-if 区别
    • 七、组件中 data 什么时候可以使用对象
    • 八、导航守卫
    • 九、keep-alive
    • 七、 r o u t e r 和 router和 router和route
    • 十、VueX
    • 十一、关于Vuex的面试题
    • 十二、vue如何实现双向数据绑定
    • 十三:MVC和MVVM
        • 1. MVC
        • 2. MVVM
    • 十四、nextTick

一、 Vue生命周期 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。(ps:生命周期钩子就是生命周期函数)例如,如果要通过某些插件操作DOM节点,如想在页面渲染完后弹出广告窗, 那我们最早可在mounted 中进行。
在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法
create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作
beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的
mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步
updated:页面显示的数据和data中的数据已经保持同步了,都是最新的
beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁
destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。
vue|Vue面试常用详细总结
文章图片

二、vue响应式原理 响应式原理指的是:在改变数据的时候,视图会跟着更新。
VUE2.0则是利用了Object.defineProperty的方法里面的setter 与getter方法的观察者模式来实现。
实现流程
data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。
Vue2.0
  • 基于Object.defineProperty,不具备监听数组的能力,需要重新定义数组的原型来达到响应式。
  • Object.defineProperty 无法检测到对象属性的添加和删除 。
  • 由于Vue会在初始化实例时对属性执行getter/setter转化,所有属性必须在data对象上存在才能让Vue将它转换为响应式。
  • 深度监听需要一次性递归,对性能影响比较大。
Vue3.0
  • 基于Proxy和Reflect,可以原生监听 数组,可以监听对象属性的添加和删除。
  • 不需要一次性遍历data的属性,可以显著提高性能。
  • Proxy是ES6新增的属性。
  • 组件实例初始化的速度提高100%
  • 使用Proxy节省以前一半的内存开销,加快速度,但是低版浏览器不兼容
通过自定义 setget 函数的方式,在原本的逻辑中插入了我们的函数逻辑,实现了在对对象任何属性进行读写时发出通知。
get 中收集依赖,在 set 派发更新,之所以 Vue3.0 要使用 Proxy 替换原本的 API 原因在于 Proxy 无需一层层递归为每个属性添加代理,一次即可完成以上操作,性能上更好,并且原本的实现有一些数据更新不能监听到,但是 Proxy 可以完美监听到任何方式的数据改变,唯一缺陷可能就是浏览器的兼容性不好了。
二·0、观察者模式 观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
**意图:**定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
三、计算属性computed 为什么用computed?
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护
computed的定义
computed是一个计算属性,当其依赖的属性的值发生变化时,计算属性会重新计算,反之,则使用缓存中的属性值。
computed里的值不可在date里面定义,因为对应的computed作为计算属性定义的值并返回对应的结果给这个变量,变量不可被重复定义和赋值
computed特性
1.是计算值,
2.应用:就是简化tempalte里面{{}}计算和处理props或$emit的传值
3.具有缓存性,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再次执行函数
四、侦听属性watch watch的定义
watch是一个监听器,用于监听响应数据的变化,是一个对象,键是需要观察的表示,值使对应的回调函数。
watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
watch特性
1.是观察的动作,
2.应用:监听props,$emit或本组件的值执行异步操作
3.无缓存性,页面重新渲染时值不变化也会执行
4、watch只能去监听一个已存在的数据
5、允许异步操作
五、computed 和 watch 区别 computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容。
computed可以监听多个属性,例如购物车商品结算,watch只能监听一条数据,例如搜索
watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。
六、v-show 与 v-if 区别 v-show 只是在 display: nonedisplay: block 之间切换。无论初始条件是什么都会被渲染出来,后面只需要切换 CSS,DOM 还是一直保留着的。所以总的来说 v-show 在初始渲染时有更高的开销,但是切换开销很小,更适合于频繁切换的场景。
v-if 的话就得说到 Vue 底层的编译了。当属性初始为 false 时,组件就不会被渲染,直到条件为 true,并且切换条件时会触发销毁/挂载组件,所以总的来说在切换时开销更高,更适合不经常切换的场景。
并且基于 v-if 的这种惰性渲染机制,可以在必要的时候才去渲染组件,减少整个页面的初始渲染开销。
七、组件中 data 什么时候可以使用对象 这道题目其实更多考的是 JS 功底。
组件复用时所有组件实例都会共享 data,如果 data 是对象的话,就会造成一个组件修改 data 以后会影响到其他所有组件,所以需要将 data 写成函数,每次用到就调用一次函数获得新的数据。
当我们使用 new Vue() 的方式的时候,无论我们将 data 设置为对象还是函数都是可以的,因为 new Vue() 的方式是生成一个根组件,该组件不会复用,也就不存在共享 data 的情况了。
组件通信
方法一、props/$emit
父组件通过 props 向下传递数据给子组件。
子组件通过 events 给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
方法二、provide/inject
八、导航守卫 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YgtXLKjV-1609408409982)(C:\Users\包大人\AppData\Roaming\Typora\typora-user-images\image-20201211110249452.png)]
1、全局守卫
  • **前置钩子:**before Each
    • 在路由改变前调用
    • 需要使用next()
    • 每当触发导航时,将按创建顺序调用全局警戒。可以异步解决保护措施,并且在解决所有挂钩之前将导航视为挂起状态。
  • 后置钩子:afterEach
    • 不需使用next()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OB5q34tv-1609408409983)(C:\Users\包大人\AppData\Roaming\Typora\typora-user-images\image-20201211110301199.png)]
2、路由独享的守卫
换句话来说就是按路线防护
您可以beforeEnter直接在路由的配置对象上定义防护:
3、组件守卫
最后,您可以使用以下选项直接在路由组件(传递给路由器配置的组件)内部定义路由导航保护:
  • beforeRouteEnter
    • 进入当前路由之前执行的函数
    • 此时实例还没被创建,不能获取实例,也就是this
  • beforeRouteUpdate
    • 当前路由改变调用
    • 该函数可以访问组件实例(this)
  • beforeRouteLeave
    • 当导航离开组件组件对应的路由时调用
    • 也能访问实例
4、路由监测变化
5、Vue-router中路由传参有几种形式?
一、vue-router路由跳转分为两大类
1、编程式的跳转:router.push
2、声明式的跳转:
二、编程式的跳转分为三种
1、this.$router.push(“detail”):detail为要跳转的路由地址,该方式简单但无法传递参数。
2、命名路由。this. r o u t e r . p u s h ( n a m e : " d e t a i l " , p a r a m s : p e r s o n I d : 33 ) : d e t a i l 为 要 跳 转 的 路 由 地 址 , p a r a m s 为 传 递 的 参 数 , 目 标 页 面 可 以 使 用 t h i s . router.push({name:"detail",params:{personId:33}}):detail为要跳转的路由地址,params为传递的参数,目标页面可以使用this. router.push(name:"detail",params:personId:33):detail为要跳转的路由地址,params为传递的参数,目标页面可以使用this.router.params.personId来获取传递的参数,该方式有一个缺点就是在目标页面刷新时传递过来的参数会丢失。
3、查询参数。this. r o u t e r . p u s h ( p a t h : " / d e t a i l " , q u e r y : p e r s o n I d : 33 ) : d e t a i l 为 要 跳 转 的 路 由 地 址 , q u e r y 为 传 递 的 参 数 , 目 标 页 面 使 用 t h i s . router.push({path:"/detail",query:{personId:33}}):detail为要跳转的路由地址,query为传递的参数,目标页面使用this. router.push(path:"/detail",query:personId:33):detail为要跳转的路由地址,query为传递的参数,目标页面使用this.router.query.personId来获取传递的参数,该方式会把传递的参数放在url上,如:localhost:8080/#/detail/?personId=33。
三、声明式的跳转分为三种(优缺点与编程式相同)
1、跳转到详情页
2、跳转到详情页
3、跳转到详情页
四、传参方式的不同点
1、query通过查询参数配合path传参,params通过命名路由配合name传参
2、通过query传递参数,参数会出现在地址栏,而params不会
3、query传递的参数在刷新后仍存在,params传递的参数在刷新后会丢失。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pbH4knZ3-1609408409987)(C:\Users\包大人\AppData\Roaming\Typora\typora-user-images\image-20201218190230353.png)]
6、完整的导航解析流程
  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
九、keep-alive keep-alivevue2.0加入的一个特性, 能缓存某个组件,或者某个路由。缓存的好处:
  1. 节省性能消耗,避免一个组件频繁重新渲染,节省开支
  2. 保存用户状态,比如说:我们在填写收货地址的页面,需要跳转到另一个页面通过定位选择地址信息再返回继续填写,这时候需要缓存收货地址页面,避免跳转页面导致用户数据丢失。
    如果你需要在组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件。
    对于 keep-alive 组件来说,它拥有两个独有的生命周期钩子函数,分别为 activateddeactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 actived 钩子函数。
基础方法:
缓存组件,被keep-alive只会渲染一次

缓存路由,所有在keep-alive标签下的路由都会被缓存 :



七、 r o u t e r 和 router和 router和route $router他是vuerouter实例应用,主要实现路由跳转,想跳转不同的路径使用router.push方法
r o u t e 是 一 个 跳 转 的 路 由 对 象 , 每 一 个 路 由 都 会 有 一 个 route是一个跳转的路由对象,每一个路由都会有一个 route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等
十、VueX 1、什么是vuex?为什么使用vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。具体是实现了一个单向数据流,在全局拥有一个state存放数据,当组件要更改State中的数据时,必须通过Muation提交修改信息,Mutation同时提供了订阅者模式供外部插件调用获取state数据的更新。
而所有的异步操作都需要走Action,但Action是无法直接修改State的,还需要通过Muation来修改state的数据。最后,根据State的变化,渲染到视图上。
什么情况下我应该使用 Vuex?
如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
2、vuex核心概念
  • State
    • VueX的唯一数据源
    • Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于与一般Vue对象里面的data
    • state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新
  • 它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
  • Mutations
    • Vuex的store状态的更新唯一方式:提交Mutation
    • 非常类似于事件
    • Muatation主要包括俩部分:
      • 字符串的事件类型(type)
      • 一个回调函数(handler),该回调函数的第一个参数就是state
      • 你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)
    • 都是同步事务
Mutation 需遵守 Vue 的响应规则
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
  1. 最好提前在你的 store 中初始化好所有所需属性。
  2. 当需要在对象上添加新属性时,你应该
  • 使用 Vue.set(obj, 'newProp', 123), 或者
  • 以新对象替换老对象。例如,利用对象展开运算符 (opens new window)我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }

使用常量替代 Mutation 事件类型
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
// mutation-types.js export const SOME_MUTATION = 'SOME_MUTATION' // store.js import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types'const store = new Vuex.Store({ state: { ... }, mutations: { // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名 [SOME_MUTATION] (state) { // mutate state } } })

在需要多人协作的大型项目中,这会很有帮助
mutation中都是同步事务
在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。
devtools无法捕捉到mutation的异步操作
  • Getters
    • 可以理解为计算属性
    • 类似与computed,具有缓存属性
    • getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
    • Getter 接受 state 作为其第一个参数
    • Getter 也可以接受其他 getter 作为第二个参数
  • Actions
    • Action类似于Muation,是用来替代Muation进行异步操作
    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作。
  • Modules
    • Vuex由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
      为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
十一、关于Vuex的面试题 1、vuex有哪几种属性? ****
答:有五种,分别是 State、 Getter、Mutation 、Action、 Module
2、vuex的State特性是?
答: 一、Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于与一般Vue对象里面的data
二、state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新
三、它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
3、vuex的Getter特性是?
答: 一、getters 可以对State进行计算操作,它就是Store的计算属性
二、 虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用
三、 如果一个状态只在一个组件内使用,是可以不用getters
4、vuex的Mutation特性是?
答: 一、Action 类似于 mutation,不同在于: 二、Action 提交的是 mutation,而不是直接变更状态。 三、Action 可以包含任意异步操作
5、Vue.js中ajax请求代码应该写在组件的methods中还是vuex的actions中?
答: 一、如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。
二、如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。如果不要复用这个请求,那么直接写在vue文件里很方便。
6、不用Vuex会带来什么问题?
答: 一、可维护性会下降,你要想修改数据,你得维护三个地方
二、可读性会下降,因为一个组件里的数据,你根本就看不出来是从哪来的
三、增加耦合,大量的上传派发,会让耦合性大大的增加,本来Vue用Component就是为了减少耦合,现在这么用,和组件化的初衷相背。 但兄弟组件有大量通信的,建议一定要用,不管大项目和小项目,因为这样会省很多事
十二、vue如何实现双向数据绑定 实现原理
  • Vue中的双向数据绑定是怎么做的?
1.vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发相应的监听回调
  • Vue中实现的具体原理?
2.核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法;
3.介绍一下Object.defineProperty()方法
(1)Object.defineProperty(obj, prop, descriptor) ,这个语法内有三个参数,分别为 obj (要定义其上属性的对象) prop (要定义或修改的属性) descriptor (具体的改变方法)
(2)简单地说,就是用这个方法来定义一个值。当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法;
实现过程
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
.VUE3.0通过Proxy来劫持数据,当数据发生变化时发出通知
  • 1 defineProperty只能监听某个属性,不能对全对象监听
  • 2 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
  • 3 可以监听数组,不用再去单独的对数组做特异性操作
  • vue3.x可以检测到数组内部数据的变化
十三:MVC和MVVM 1. MVC MVC 是 Model View Controller 的缩写
  • Model:模型层,是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
  • View:视图层,用户界面渲染逻辑,通常视图是依据模型数据创建的。
  • Controller:控制器,数据模型和视图之间通信的桥梁,通常控制器负责从事图读取数据,控制用户输入,并向模型发送数据。
vue|Vue面试常用详细总结
文章图片

MVC的思想:Controller负责将Model的数据用View显示出来,换句话说就是在Controller里面把Model的数据赋值给View。
MVC的特点:实现关注点分离,即应用程序中的数据模型与业务和展示逻辑解耦。就是将模型和视图之间实现代码分离,松散耦合,使之成为一个更容易开发、维护和测试的客户端应用程序。
MVC的优点:
  • 耦合度低,视图层和业务层分离
  • 重用度高
  • 生命周期成本低
  • 可维护性高
  • 部署快
MVC的缺点:
  • 不适合小型项目的开发
  • 视图与控制器间的过于紧密的连接,视图与控制器是相互分离,但却是联系紧密的部件,妨碍了他们的独立重用
  • 降低了视图对模型数据的访问,依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。
MVC的应用:主要用于中大型项目的分层开发。
MVC的例子: 举一个例子,页面有一个 id 为 container 的 span,点击按钮会让其内容加 1:
view:
id="container">0
1234

controller:
const button = document.getElementById('btn'); // 响应视图指令 button.addEventListener('click', () => { const container = document.getElementById('container'); // 调用模型 add(container); }, false); 12345678

model:
function add (node) { // 业务逻辑处理 const currentValue = https://www.it610.com/article/parseInt(node.innerText); const newValue = currentValue + 1; // 更新视图 node.innerText = current + 1; } 12345678

这样就把数据更新分的比较明确了。
2. MVVM MVVM是Model-View-ViewModel的简写,即模型-视图-视图模型。
  • Modal:模型,指的是后端传递的数据。
  • View:视图,指的是所看到的页面。
  • ViewModal:视图模型,mvvm模式的核心,它是连接view和model的桥梁。主要用来处理业务逻辑
vue|Vue面试常用详细总结
文章图片

它有两个方向:
  • 一是将模型转化成视图,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。
  • 二是将视图转化成模型,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。
这两个方向都实现的,就是数据的双向绑定。
MVVM的特点: 在MVVM的框架下,视图和模型是不能直接通信的,它们通过ViewModal来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。
MVVM的优点:
MVVM模式的主要目的是分离视图(View)和模型(Model),有几大优点:
  • 低耦合,视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
  • 可重用性,可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
  • 独立开发,开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码。
  • 可测试,界面向来是比较难于测试的,而现在测试可以针对ViewModel来写
  • 双向数据绑定,它实现了View和Model的自动同步,当Model的属性改变时,不需要手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变
MVVM适用场景: 适合数据驱动的场景,数据操作比较多的场景
十四、nextTick
  • 什么是nextTick?
    nextTick是在DOM更新完毕之后执行一个回调
  • 【vue|Vue面试常用详细总结】nextTick实现原理?
    1. Vue中用异步队列的方式来控制DOM更新和nextTick回调的先后执行
    2. microtask因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕
    3. 因为兼容性问题,vue不得不做了mickrotask向macrotask的降级方案

    推荐阅读