一篇由简到难的 Vue 面试题+详解答案

本文详细介绍了 Vue.js 框架中的重要概念,包括 MVVM 模式、数据绑定、组件通信、生命周期、指令、单向数据流、计算属性与监听器的区别、Vue 的响应式原理、以及 Vue2 和 Vue3 的响应式差异。文中通过对比 MVC 和 MVVM,解析 Vue 如何实现数据和视图的同步,并探讨了 Vue 中的 `$refs` 为何不符合 MVVM 规范。此外,还深入讨论了 `data` 为何为函数、组件间的多种通信方式、生命周期钩子的使用时机,以及 `v-if` 和 `v-show` 的应用场景。文章还涵盖 Vue 的内置指令、虚拟 DOM 的优缺点、Vue3.0 的变化,以及 Vue 中的设计模式和性能优化策略。最后,详细阐述了 `Vue.set` 的作用和原理,以及 `Vue.mixin`、`nextTick` 和 `keep-alive` 的使用场景和背后的实现机制。
摘要由CSDN通过智能技术生成
  • Model(模型):是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据

  • View(视图):是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的

  • Controller(控制器):是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据

mvc.png

MVC 的思想:一句话描述就是 Controller 负责将 Model 的数据用 View 显示出来,换句话说就是在 Controller 里面把 Model 的数据赋值给 View。

MVVM

MVVM 新增了 VM 类

  • ViewModel 层:做了两件事达到了数据的双向绑定 一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。

mvvm.png

MVVM 与 MVC 最大的区别就是:它实现了 View 和 Model 的自动同步,也就是当 Model 的属性改变时,我们不用再自己手动操作 Dom 元素,来改变 View 的显示,而是改变属性后该属性对应 View 层显示会自动改变(对应Vue数据驱动的思想)

整体看来,MVVM 比 MVC 精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作 DOM 元素。因为在 MVVM 中,View 不知道 Model 的存在,Model 和 ViewModel 也观察不到 View,这种低耦合模式提高代码的可重用性

注意:Vue 并没有完全遵循 MVVM 的思想 这一点官网自己也有说明

vue-mvvm.png

那么问题来了 为什么官方要说 Vue 没有完全遵循 MVVM 思想呢?

  • 严格的 MVVM 要求 View 不能和 Model 直接通信,而 Vue 提供了 $refs 这个属性,让 Model 可以直接操作 View,违反了这一规定,所以说 Vue 没有完全遵循 MVVM。

2 为什么 data 是一个函数

组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果

3 Vue 组件通讯有哪几种方式
  1. props 和  父组件向子组件传递数据是通过 传递的,子组件传递数据给父组件是通过 emit 触发事件来做到的

  2. children 获取当前组件的父组件和当前组件的子组件

  3. 和 listeners A->B->C。Vue 2.4 开始提供了  和 listeners 来解决这个问题

  4. 父组件中通过 provide 来提供变量,然后在子组件中通过 inject 来注入变量。(官方不推荐在实际业务中使用,但是写组件库时很常用)

  5. $refs 获取组件实例

  6. envetBus 兄弟组件数据传递 这种情况下可以使用事件总线的方式

  7. vuex 状态管理

4 Vue 的生命周期方法有哪些 一般在哪一步发请求

「beforeCreate」 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问

「created」 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。这里没有  如果非要想与 进行交互,可以通过 nextTick 来访问 Dom

「beforeMount」 在挂载开始之前被调用:相关的 render 函数首次被调用。

「mounted」 在挂载完成后发生,在当前阶段,真实的 Dom 挂载完毕,数据完成双向绑定,可以访问到 Dom 节点

「beforeUpdate」 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁(patch)之前。可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程

「updated」 发生在更新完成之后,当前阶段组件 Dom 已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新,该钩子在服务器端渲染期间不被调用。

「beforeDestroy」 实例销毁之前调用。在这一步,实例仍然完全可用。我们可以在这时进行善后收尾工作,比如清除计时器。

「destroyed」 Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

「activated」 keep-alive 专属,组件被激活时调用

「deactivated」 keep-alive 专属,组件被销毁时调用

异步请求在哪一步发起?

可以在钩子函数 created、beforeMount、mounted 中进行异步请求,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。

如果异步请求不需要依赖 Dom 推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:

  • 能更快获取到服务端数据,减少页面 loading 时间;

  • ssr  不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;

5 v-if 和 v-show 的区别

v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。

v-show 会被编译成指令,条件不满足时控制样式将对应节点隐藏 (display:none)

「使用场景」

v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景

v-show 适用于需要非常频繁切换条件的场景

扩展补充:display:none、visibility:hidden 和 opacity:0 之间的区别?

display.png

6 说说 vue 内置指令

内置指令.png

7 怎样理解 Vue 的单向数据流

数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

注意:在子组件直接用 v-model 绑定父组件传过来的 prop 这样是不规范的写法 开发环境会报警告

如果实在要改变父组件的 prop 值 可以再 data 里面定义一个变量 并用 prop 的值初始化它 之后用 $emit 通知父组件去修改

8 computed 和 watch 的区别和运用的场景

computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容,它可以设置 getter 和 setter。

watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。

计算属性一般用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑

计算属性原理详解 传送门[1]

侦听属性原理详解 传送门[2]

9 v-if 与 v-for 为什么不建议一起使用

v-for 和 v-if 不要在同一个标签中使用,因为解析时先解析 v-for 再解析 v-if。如果遇到需要同时使用时可以考虑写成计算属性的方式。


中等

10 Vue2.0 响应式数据的原理

整体思路是数据劫持+观察者模式

对象内部通过 defineReactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存放他所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新(派发更新)。

相关代码如下

class Observer {

// 观测值

constructor(value) {

this.walk(value);

}

walk(data) {

// 对象上的所有属性依次进行观测

let keys = Object.keys(data);

for (let i = 0; i < keys.length; i++) {

  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值