【前端面试题】:Vue篇

1.Vue 的核心是什么?

Vue 是一套构建用户界面的渐进式自底向上增量开发的 MVVM 框架, vue 的核心只关注视图层,
核心思想:

  • 数据驱动:使数据和视图之间保持高度一致。当数据发生变化时,Vue 能够自动更新视图,无需手动操作 DOM,极大地简化了开发流程。这种机制基于 MVVM 框架实现,通过 ViewModel 作为数据和视图之间的桥梁,实现了数据的双向绑定和自动更新。
  • 组件化:将页面拆分成多个独立的、可复用的组件。每个组件都封装了特定的功能和样式,可以方便地组合和重用,提高了代码的可维护性和可复用性。组件化开发使得页面布局更加灵活和易于管理,同时也降低了代码的耦合度,提高了开发效率。

2.请简述 vue 的单向数据流?

单向数据流,它从父组件流向子组件,通过 props 实现。这种设计确保了数据的权威性和一致性,避免了多个组件同时修改数据导致的问题。子组件不能直接修改通过 props 接收的数据,而是需要通过触发事件将数据发送回父组件,由父组件来更新数据。(可以使用 data 和 computed 解决)

3.Vue 组件之间的通信方式的几种方法?

  1. props / emit

    • props:父组件通过props向子组件传递数据。
    • $emit:子组件通过$emit触发事件,父组件监听这个事件并接收数据。
  2. attrs / listeners

    • $attrs:包含父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=“$attrs” 传入内部组件——在创建高阶组件的时候非常有用。
    • $listeners:包含了父作用域中 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=“$listeners” 传入内部组件——在创建高阶组件的时候非常有用。
  3. 父链 / 子链(parent / children)

    在 Vue.js 中,$parent$children 属性可以用于直接访问组件的父级和子级实例,从而进行组件间的通信。然而,这种方法并不推荐用于常规的组件通信,因为它破坏了组件的封装性,使得组件之间的耦合度过高。但在某些特定场景下,如果你确实需要使用这种方法,下面是一个简单的示例:

  4. provide / inject

    • provideinject 绑定在一起,允许祖先组件向其所有子孙组件提供一个依赖。不论组件层次有多深,只要使用了provideinject就可以提供和接收数据。
  5. Vuex

    • Vuex 是 Vue.js 的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
  6. Event Bus

    • 通过创建一个新的 Vue 实例作为中央事件总线,用于在组件之间传递事件与数据。
  7. slot 插槽

    • 通过插槽内容分发,实现父组件向子组件传递 HTML 结构或组件,子组件通过元素定义插槽的位置。
  8. ref

    • 在子组件上添加ref属性,父组件可以通过this.$refs直接访问子组件实例或 DOM 元素。
  9. provide / inject 的替代方案:使用 context

    • 在高阶组件或函数式组件中,可以通过context对象(包含attrsslotsemit等属性)来传递数据和方法。
  10. 全局混入

  • 通过 Vue.mixin() 方法可以创建全局混入,影响每一个之后创建的 Vue 实例。可以用来添加全局方法或属性。

Vue 组件之间的通信方式的使用方法: Vue组件通信秘籍:掌握这10大绝招,轻松玩转组件间数据传递

4.简单聊聊 new Vue 以后发生的事情?

  1. Vue 实例初始化: Vue 开始创建一个新的 Vue 实例,将负责管理应用的状态和行为。在这个过程中,Vue 会合并和处理用户传入的选项对象,包括数据(data)、方法(methods)、计算属性(computed)、生命周期钩子(如 created, mounted 等)等
  2. 数据响应式处理::Vue 会对 data 选项中的数据进行处理,将其转化为响应式对象。当这些数据发生变化时,Vue 能够自动感知并触发视图的更新。
  3. 模板编译: 如果提供了 template 选项,Vue 会将其编译成渲染函数。渲染函数是一个能够返回虚拟 DOM 的 JavaScript 函数,它根据模板和数据生成虚拟 DOM 树。
  4. 创建虚拟 DOM: Vue 根据渲染函数生成一个初始的虚拟 DOM 树。虚拟 DOM 是一个轻量级的 JavaScript 对象,它描述了真实 DOM 的结构。
  5. 挂载到真实 DOM: Vue 实例将虚拟 DOM 渲染为真实 DOM,并将其挂载到指定的 HTML 元素上。完成挂载后,Vue 实例可以响应用户的交互,并监听数据变化。
  6. 数据变化与更新: 一旦 Vue 实例被挂载,它就开始监听数据的变化。当数据发生变化时,Vue 会重新运行渲染函数,生成新的虚拟 DOM 树,并与旧的虚拟 DOM 树进行比较(diff)。然后,Vue 会最小化地更新真实的 DOM,以反映数据的变化。

5.简述 Vue 如何检测数组变化 ?

Vue 可以通过几种方式检测数组变化并响应式地更新视图:

  1. 使用 Vue 实例的 vm.$set 方法来更新数组中的元素。这样做可以确保 Vue 能够追踪变化。

  2. 直接用索引赋值来替换数组中的元素,但是这种方式不会触发视图更新,除非你使用 Vue.set。

  3. 使用原生的 JavaScript 方法,如 push、pop、shift、unshift、splice 和 sort 来修改数组,Vue 会自动检测这些方法的变化。

  4. 使用 vm.$forceUpdate() 强制 Vue 实例重新渲染,但这种方式应该谨慎使用,因为它会造成不必要的性能开销。

  5. 使用 Vue.set 或 Vue.delete 方法来添加或删除数组中的元素,这样做可以确保响应式系统能够追踪变化。




6.如何理解 Vue 中的模板编译原理?

Vue 2 的模板编译原理是将模板字符串转换为渲染函数,并通过比较虚拟 DOM 来高效更新视图的过程。这一机制使得 Vue 2 能够灵活地处理模板,并根据数据的变化高效地更新视图。以下是 Vue 2 模板编译原理的详细步骤:

  1. 模板解析
    Vue 2 的编译器首先会对模板字符串进行解析。解析器会将模板中的 HTML 标签、属性、文本内容等转换为抽象语法树(AST)。AST 是一个以 JavaScript 对象形式表示的树状结构,它准确地描述了模板的结构和语义。

  2. 优化 AST
    在生成 AST 之后,Vue 2 会进行一系列的优化操作。其中一个重要的优化是静态树提升(Static Tree Hoisting)。编译器会遍历 AST,标记出那些不会随数据变化而变化的静态节点。在后续的渲染过程中,这些静态节点会被跳过,从而大大提高了渲染性能。

  3. 生成渲染函数
    使用优化后的 AST,Vue 2 会生成一个渲染函数。渲染函数是一个纯 JavaScript 函数,它接收一个包含 Vue 实例数据的上下文对象,并返回一个虚拟 DOM 节点。这个虚拟 DOM 节点是一个轻量级的 JavaScript 对象,它描述了真实 DOM 的结构和属性。

  4. 虚拟 DOM 渲染
    当 Vue 实例的数据发生变化时,Vue 2 会重新运行渲染函数,生成新的虚拟 DOM。然后,Vue 会使用一个高效的 diff 算法来比较新旧两个虚拟 DOM 之间的差异。这个算法能够计算出最小的 DOM 操作步骤,使得旧的 DOM 能够转变为新的 DOM。最后,Vue 将这些操作应用到真实的 DOM 上,完成视图的更新。

7.请解释 Vue 为什么要用虚拟 Dom,详细解释原理 ?

Vue 使用虚拟 DOM 的原因主要在于优化性能、提高开发效率和实现跨平台能力。其原理涉及将真实 DOM 树抽象为虚拟 DOM 树,并通过比较新旧虚拟 DOM 树来最小化 DOM 操作,从而避免不必要的性能损耗。

  1. 性能优化: 在 Vue 中,每当组件的状态发生变化时,都需要重新渲染视图。如果直接操作真实 DOM,会涉及到大量的 DOM API 调用,导致浏览器进行重排和重绘,性能开销较大。而虚拟 DOM 则是一个轻量级的 JavaScript 对象,它的创建、更新和比较的成本相对较低。Vue 通过比较新旧虚拟 DOM 的差异,计算出最小的 DOM 操作步骤,然后一次性将这些操作应用到真实的 DOM 上,从而避免了大量无谓的计算和 DOM 操作,提高了渲染性能。

  2. 提高了开发效率,由于虚拟 DOM 是一个 JavaScript 对象,我们可以使用 JavaScript 的所有功能来操作和查询它,这使得开发过程更加灵活和方便。同时,虚拟 DOM 也使得 Vue 能够支持更复杂的组件嵌套和组合,提高了代码的可维护性和复用性。

  3. 够实现跨平台能力: 虚拟 DOM 不仅可以在浏览器环境中运行,还可以在服务器、移动设备等其他环境中运行。这使得 Vue 能够支持多种平台的开发,如 Web、移动应用、桌面应用等,实现了代码的复用和共享。

实现虚拟 DOM 的渲染原理:

  1. 将模板编译成虚拟 DOM 树。当 Vue 组件的状态发生变化时,Vue 会重新编译模板,生成新的虚拟 DOM 树。
  2. 比较新旧虚拟 DOM 树。Vue 使用一个高效的 diff 算法来比较新旧两个虚拟 DOM 树,找出它们之间的差异。
    3. 更新真实 DOM。根据比较结果,Vue 计算出最小的 DOM 操作步骤,并一次性将这些操作应用到真实的 DOM 上,完成视图的更新。

8.说说 Vue 实例挂载过程?

  1. 创建 Vue 实例: 通过调用 Vue 构造函数,创建一个 Vue 实例,并传入配置对象。

  2. 初始化: 在初始化阶段,Vue 会进行一系列的初始化操作,包括合并配置项、初始化生命周期钩子、初始化事件系统、初始化响应式数据等。

  3. 模板编译: 如果配置对象中存在 template 选项,Vue 会将模板编译成渲染函数。渲染函数是 Vue 中用于生成虚拟 DOM 的函数。

  4. 创建虚拟 DOM: 通过调用渲染函数,Vue 会根据模板生成虚拟 DOM(Virtual DOM)。虚拟 DOM 是一个轻量级的 JavaScript 对象,它描述了真实 DOM 的结构和属性。

  5. 执行挂载函数: Vue 会调用 mount 函数,将虚拟 DOM 渲染成真实 DOM,并将其插入到页面中指定的挂载点上。

  6. 数据响应式: 在挂载完成后,Vue 会对数据进行响应式处理。当数据发生变化时,Vue 会自动更新相关的视图。

  7. 完成挂载: Vue 实例挂载完成后,会触发 mounted 生命周期钩子函数。在这个阶段,可以进行一些初始化的异步操作,或者与外部库进行交互。

9.vue-router 里的router-link标签和a标签有什么区别?

标签是 HTML 中用于创建链接的标准元素,其 href 属性指向目标 URL,点击后浏览器会导航至新页面,这通常会导致页面的重新加载。

是 Vue.js 的 vue-router 插件提供的一个组件,用于在 Vue 应用中实现单页面应用的路由跳转。通过设置 to 属性,可以指定目标路由路径,实现组件间的切换,而不会导致整个页面的重载或刷新。这种方式可以提高应用的性能,因为只有与当前路由相关的组件会被渲染或更新。

10.v-show 与 v-if 的区别?

  1. 渲染方式

    • v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。当 v-if 的值为 false 时,对应的元素及其子元素都不会被渲染到 DOM 中。只有当条件变为 true 时,元素才会被重新渲染。
    • v-show 就简单得多——不论初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。也就是说,v-show 只是简单地切换元素的 display CSS 属性。
  2. 性能考虑

    • 由于 v-if 有更高的切换开销,如果你需要频繁切换一个元素,使用 v-show 会更加高效,因为它只是简单地切换 CSS 属性,而不会涉及元素的销毁和重建。
    • 但是,如果元素在初始渲染后很少改变,那么 v-ifv-show 的性能差异几乎可以忽略不计。
  3. 初始渲染

    • v-if 的条件为 false 时,对应的元素在初始渲染时就不会被渲染到 DOM 中。
    • v-show 无论条件如何,都会进行初始渲染,只是通过 CSS 控制其显示或隐藏。
  4. 使用场景

    • v-if 更适合在运行时条件很少改变时使用,比如根据用户权限渲染不同的内容。
    • v-show 更适合需要频繁切换显示/隐藏状态的元素,比如切换按钮的可见性。。

11.v-if 和 v-for 为什么不建议混合使用?

  1. 性能问题
    v-ifv-for 一起使用时,Vue 会首先计算 v-for,然后为每一个元素渲染 v-if。这意味着,即使 v-if 的条件不满足,Vue 也会先遍历整个列表并计算每一个元素的渲染,这可能导致不必要的性能损耗。如果列表很大,那么这种性能损耗可能会更加明显。

  2. 渲染逻辑不明确
    混合使用 v-ifv-for 可能会使得渲染逻辑变得复杂和难以理解。通常,我们期望 v-for 仅仅是用来遍历列表并渲染元素,而 v-if 则用于基于条件决定是否渲染某个元素。将两者混合使用可能会使得这种区分变得模糊,增加了代码维护的难度。

  3. 优先级问题
    在 Vue 中,v-for 的优先级高于 v-if。这意味着,即使 v-if 的条件不满足,v-for 也会首先被计算。这可能会导致一些预期之外的行为,特别是当 v-if 的条件依赖于 v-for 遍历的元素时。

更好的替代方案
通常,我们可以使用计算属性(computed properties)或方法来替代混合使用 v-ifv-for。例如,我们可以在计算属性中先根据条件过滤列表,然后再在模板中使用 v-for 遍历过滤后的列表。这样,我们就可以避免混合使用 v-ifv-for,同时还能保持代码的清晰和高效。

12.Vue 项目时为什么要在列表组件中写 key,其作用是什么?

在 Vue 项目中,当我们使用 v-for 指令来遍历数组并渲染列表组件时,为每一个组件项提供一个唯一的 key 属性是非常重要的。这个 key 属性的主要作用有以下几点:

  1. 追踪每个节点的身份:Vue 使用 key 来跟踪每个节点的身份,从而重用和重新排序现有元素。当列表项的顺序改变时,Vue 能够基于 key 的值来识别每个列表项,并相应地移动它们,而不是重新渲染整个列表。这大大提高了列表渲染的性能。
  2. 提升渲染性能:由于 Vue 能够基于 key 高效地更新虚拟 DOM,因此它可以更快速地更新视图。如果没有 key,Vue 将使用一种更通用的就地复用策略,这可能导致不必要的组件状态混乱或更新错误。
  3. 维护组件状态:在列表渲染中,如果组件具有内部状态(例如,输入框的值或复选框的选中状态),使用 key 可以确保当列表项的顺序改变或添加/删除列表项时,每个组件的状态得到正确的维护。如果没有 key,Vue 可能无法准确地关联组件状态和列表项,导致状态丢失或混乱。
  4. 更可靠的更新策略:使用 key 可以使 Vue 的更新策略更加可靠和可预测。Vue 可以根据 key 的变化来确定哪些组件需要被创建、更新或销毁,从而避免了不必要的操作和潜在的错误。

综上所述,为列表组件中的每一项提供唯一的 key 属性是 Vue 开发中的一个重要实践,它有助于提高渲染性能、维护组件状态并确保更可靠的更新策略。

13.vue 中为什么使用 v-for 时不能用 index 作为 key?

  1. 状态不稳定: 在 Vue 的开发中,数据是动态变化的,当数据发生变化时,新的元素可能被添加到数组的开头、中间或末尾等位置,这样原本的 index 值就会发生改变,导致 key 与实际内容不匹配,可能会出现渲染错误或性能下降的问题。

  2. 列表重新排序时可能引发错误: 当列表中的元素需要重新排序时,如果我们使用 index 作为 key 值,Vue 会认为只是简单的更新了元素的位置,而不是重新创建新元素,这可能会导致列表顺序混乱或出现奇怪的 BUG。

  3. 对可访问性的影响: 如果使用 index 作为 key 值,可能会导致不利于屏幕阅读器和键盘导航器的访问,因为这些助力技术可能依赖于 key 值来确定元素的唯一性。

14.vue 在 v-for 时给每项元素绑定事件需要用事件代理吗?为什么?

vue 本身不做事件代理

  1. 普通 html 元素和在组件上挂了.native 修饰符的事件。最终 EventTarget.addEventListener()挂载事件;

  2. 组件上的,vue 组件实例上的自定义事件(不包括.native)会调用原型上的$on,$emit(包括一些其他 api $off,$once 等等);

vue 自身没有做事件代理,如果需要,则直接代理到父节点;

15.简述 v-model 双向绑定的原理是什么?

原理: 数据劫持 + 发布者-订阅者模式 实现。
是的,您总结得非常准确。v-model 在 Vue.js 中实现的原理确实是基于数据劫持(响应式系统)和发布者-订阅者模式。

数据劫持

Vue.js 利用 JavaScript 的 Object.defineProperty(在 Vue 2.x 中)或 Proxy(在 Vue 3.x 中)来实现数据劫持。这意味着当数据发生变化时,Vue 能够自动感知到这些变化,并触发相应的更新操作。在 Vue 的响应式系统中,每个响应式数据都被包装成一个 Observer 对象,该对象会转换数据的 getter 和 setter,使得数据在访问和修改时能够触发依赖更新。

发布者-订阅者模式

Vue 的响应式系统还使用了发布者-订阅者模式(也称为观察者模式)。当数据发生变化时,它就像是一个发布者,通知所有订阅了这个数据的订阅者(Watcher)。这些订阅者通常是与数据相关的视图组件或计算属性。当数据变化时,发布者会触发订阅者的更新函数,从而更新视图或重新计算属性值。

v-model 的工作原理

  1. 数据劫持v-model 绑定的数据被 Vue 的响应式系统处理,变为响应式数据。

  2. 创建订阅者:当组件渲染时,如果模板中有使用了 v-model 的表单元素,Vue 会为这些元素创建对应的 Watcher(订阅者),用于监听数据的变化。

  3. 视图到数据的绑定:表单元素的事件(如 input 事件)会被 v-model 指令处理,当事件触发时,它会更新对应的数据属性。

  4. 数据到视图的绑定:当数据属性通过 JavaScript 代码或其他方式被更新时,Vue 的响应式系统会触发所有订阅了该数据的 Watcher 进行更新,从而更新视图。

16.双向绑定和 vuex 是否冲突?

在 Vue 中,双向绑定和 Vuex 并不直接冲突,但在某些特定情况下可能会引起问题。在 Vuex 的严格模式下,对 state 的修改只能在 mutation 中进行。这意味着双向绑定的 v-model 不能直接用于 state 上,因为当输入框内容改变时,如果试图直接修改 state,就会抛出错误。这是因为 v-model 的双向绑定特性与 Vuex 的单向数据流原则相冲突。
解决方案:

  • 给 Input标签绑定 value,然后侦听 input 或者 change 事件,在事件回调中 调用一个方法;
  • 使用带有 setter 的双向绑定计算属性;

17.v-on 可以监听多个方法吗?怎么实现?

在 Vue.js 中,v-on 指令可以用来监听多个方法。这可以通过为同一个元素绑定多个事件处理程序来实现。例如,您可以为一个按钮同时绑定 click 和 dblclick 事件,这样当该按钮被点击或双击时,都会触发相应的方法。

以下是一个简单的示例:




18.请简述 为什么要使用 v-cloak?v-cloak 的作用?

在 Vue 中,v-cloak 是一个用于解决插值表达式闪烁问题的指令。当 Vue 实例渲染完成前,插值表达式会显示为未编译的原始数据内容,这可能导致页面上出现短暂的闪烁。使用 v-cloak 指令可以在 Vue 实例还未完全编译之前隐藏相关元素,直到 Vue 完成编译和渲染后再显示它们,从而防止插值表达式的闪烁问题。

在我们的 Vue 模板中,我们可以将 v-cloak 指令应用于需要隐藏的元素:

<div v-cloak>{{ message }}div>

为了使 v-cloak 生效,需要在样式表中添加相应的 CSS 规则:

[v-cloak] {
  display: none;
}

在 Vue 实例编译之前,元素会被隐藏起来,避免了初始状态下的插值表达式显示问题。一旦 Vue 实例编译完成,CSS 规则会被应用到元素上,使其显示出来,从而避免了页面加载过程中的插值表达式显示问题。

19.keep-alive 的作用是什么?

在 Vue 中,keep-alive是一个内置组件,它主要用于缓存不活动的组件实例,以避免重复渲染相同的组件,从而提高页面性能和用户体验。

作用

  1. 性能优化:通过缓存组件实例,避免了每次切换组件时都重新创建和销毁组件的开销,减少了 DOM 操作,从而提高了页面渲染性能。
  2. 状态保留:缓存的组件实例在切换回来时,其状态会被保留,包括数据、事件监听器以及 DOM 结构等,这使得用户可以无缝地返回到之前的状态,提高了用户体验。

原理

keep-alive组件会创建一个名为 cache 的缓存对象,用来存储被缓存的组件实例。当一个被keep-alive包裹的组件切换出去时,其实例会被缓存到 cache 中。当再次需要渲染这个组件时,如果之前被缓存的组件实例存在,则会直接从缓存中取出实例,并重新挂载到 DOM 上。

应用场景

  1. 前进后退页面缓存:在一些需要用户频繁前进后退的场景中,如列表页和详情页的切换,使用keep-alive可以缓存页面组件,使得用户在返回时能够迅速恢复之前的状态,避免重新加载数据。
  2. 条件渲染缓存:当组件的渲染受到条件控制(如 v-if 或 v-show),并且希望组件在条件改变时保留其状态时,可以使用keep-alive来缓存组件。
  3. 路由缓存:在 Vue Router 中,可以通过在路由配置中添加meta属性,并设置keepAlivetrue,来实现对路由组件的缓存。这样,当用户在不同路由之间切换时,可以保留特定路由组件的状态。

此外,keep-alive还提供了includeexclude属性,允许开发者指定哪些组件需要被缓存,哪些组件不需要被缓存。这增加了缓存策略的灵活性,使得开发者可以根据实际需求来定制缓存行为。
需要注意的是,虽然keep-alive能够提高性能和用户体验,但过度使用也可能导致内存占用过多。因此,在使用时需要权衡利弊,根据具体的应用场景和需求来决定是否使用以及如何使用。

20.vue 常见指令有哪些?

  1. v-text:用于更新元素的文本内容。它会根据表达式的值来更新元素的文本内容。

  2. v-html:用于更新元素的 innerHTML。与 v-text 不同,它可以解析 HTML 标签。

  3. v-show:根据表达式的真假值来切换元素的 display CSS 属性。

  4. v-if:根据表达式的真假值来条件性地渲染元素。如果为假,则元素及其子元素都不会被渲染到 DOM 中。

  5. v-else:与 v-ifv-else-if 一起使用,表示当条件不满足时渲染的元素。

  6. v-else-if:允许为 v-ifv-else-if 添加条件。

  7. v-for:用于基于源数据多次渲染一个元素或模板块。可以用于数组或对象。

  8. v-bind:或简写为 :,用于响应式地更新 HTML 属性。例如,绑定一个元素的 classstyle

  9. v-on:或简写为 @,用于监听 DOM 事件,并在触发时执行一些 JavaScript 代码。

  10. v-model:实现表单输入和应用状态之间的双向绑定。通常用于