vue2+vue3面试题 高频 2025 (1-14) 题

一. 谈一谈你对vue的理解?

1.1  vue是一套用于构建用户界面的渐进式框架, Vue的核心库只关注视图层 


渐进式: 你可以只使用Vue的一部分功能,也可一根据项目需求,逐步引入更多功能,最终搭建完整应用

1.2 声明式框架

  • 早在jq的时代编写的代码都是命令式的,命令式框架重要特点就是关注过程
  • 声明式框架更加关注结果,命令式的代码封装到了Vuejs中,过程靠Vuejs来实现 

1.3 MVVM 模式 

目的: 职责划分,分成管理

1. MVC 全称 Model-View-Controller 

  • Model: 数据层(比如数据库或业务逻辑)
  • View: 视图层(用户看到的页面)
  • Controller: 控制器,负责接受用户操作,更新模型或视图

举例 

用户点击按钮->控制器接受点击->改变数据模型->在通知视图更新 

2.MVVM 

全称: Model- View -ViewModel 

  • Model: 数据层
  • view : 视图层
  • ViewModel: 视图模型,连接View和Model的桥梁,通过双向数据绑定实现同步

Model ↔ ViewModel ↔ View (双向绑定

vue本身就是MVVM的一个实践框架: 

  • data( ) 是Model 
  • template 是View 
  • Vue实例作为ViewModel,负责响应式绑定和数据变化侦测
  • 用户操作页面(View)后,Vue会自动把值更新到数据(Model),反之亦然

1.4 采用虚拟DOM

虚拟DOM是js对真实DOM的一种表示,简单理解,就是把HTML元素结构用js对象表示,后续用它来更新页面

因为操作真实DOM非常慢,所以: Vue,React等框架使用虚拟DOM来先做内存中的计算,再统一最小化地更新真实DOM 

工作流程: 

【数据变化】→ 【生成新的虚拟 DOM】 → 【和旧的虚拟 DOM 做对比(Diff 算法)】
        → 【找出差异】 → 【最小化更新真实 DOM】

 1.5 组件化 

组件化就是把有页面拆分成一个个小的,独立的,可服用的功能模块(组件)来开发和维护,每个组件就是一个包含自己结构,样式,逻辑的独立单元

为什么要组件化?

1. 解耦: 每个模块职责单一,逻辑清晰,互不影响 

2. 复用: 封装成组件后可以在多个页面或项目中服用

3. 便于协作: 多人开发时可以按组件划分任务,互不冲突

1.6 区分编译打包和运行(浏览器)时

1. 编译时: 

  • Vue文件中的写的<template>,<script><style>会被拆分解析
  • 例如 .vue文件会被编译成渲染函数(render function)
  • ES6+ 会被Babel 编译为ES5,以适配老浏览器
  • SCSS/LESS 也会被编译为CSS 

2.打包时

  • 把项目中引用的模块(组件,依赖库等)合并为一份或几份压缩后的js/css文件
  • 会进行Tree-Shaking(去除未使用代码),压缩混淆,代码分割等优化

工具: Webpack/Vite 

目的: 提高加载速度,适应线上部署

3.运行时

  • 项目代码已加载到浏览器,JS开始执行
  • Vue会创建响应式系统,挂在组件,绑定DOM 
  • 用户交互时,触发事件,修改数据,触发虚拟DOM更新

依赖: 浏览器环境,DOM,Vue的runtime包 

二. 谈一谈你对SPA的理解 

1.1. 理解基本概念

  • SPA 单页应用,默认情况下我们编写Vue,React都只有一个html页面,并且提供一个挂载点,最终打包后会再此页面中引入对应的资源(页面的渲染全部是由JS动态进行渲染的),而不是每次跳转都重新加载页面. 
  • MPA 多页应用,多个html页面,每个页面必须重复加载,js,css等相关资源,服务端返回完整的html,同时数据也可以再后端进行获取一并返回"模版引擎". 多页应用跳转需要整页资源刷新, 服务器端渲染SSR

    如何分清在哪渲染: HTML是在前端动态生成的"客户端渲染",在服务端处理好并返回的是"服务端渲染". 

1.2 SPA的特点

1. 优点 

  • 用户体验好: 页面不刷新,加载速度快,交互流畅
  • 前后端分离: 前端负责页面逻辑,后端只提供API 
  • 组件化开发: 配合Vue等框架实现模块化开发,易维护,易复用

2. 缺点: 

  1. 首屏加载慢: 需要一次加载大量JS,影响首次打开速度
  2. SEO不友好: 因为页面是通过JS动态渲染的,搜索引擎难以抓取
  3. 前端逻辑复杂: 需要自己处理路由,状态管理,权限控制 

3.SPA单页和多页MPA对比

对比项SPA(单页应用)MPA(多页应用)
页面数量一个 HTML,内容动态切换多个 HTML,每个页面独立
路由处理前端路由(如 Vue Router)传统后端路由(服务端返回页面)
页面刷新不刷新页面,内容局部更新每次跳转都刷新页面
SEO 支持差,需要配 SSR好,天然支持搜索引擎
首屏速度慢(需加载 JS)快(每个页面加载需要的内容)

三. Vue为什么需要虚拟DOM?

1.1 基本概念 

基本上所有框架都引入了虚拟DOM来对真实DOM进行抽象,也就是现在大家所熟知的VNode(虚拟)和VDOM(虚拟DOM) 
 

  • Virtual DOM 就是用js对象来描述真实DOM,是对真实DOM的抽象,由于直接操作DOM性能低但是js层的操作效率高,可以将DOM操作转化成对象操作,最终通过diff算法比对差异进行更新DOM(减少了对真实DOM的操作). 
  • 虚拟DOM不依赖真实平台环境从而也可以实现跨平台 

1.2 补充:VDOM是如何生成的?

  • 在vue中我们常常会为组件编写模版 - template 
  • 这个模版会被编译器编译为渲染函数- render 
  • 在接下来的挂在过程会diaoyongrender函数,返回的对象就是虚拟dom 
  • 会在后续的patch过程中进一步转化为真实dom 

1.3 再次补充: VDOM如何做diff的?

  • 挂在过程结束后,会记录第一次生成的VDOM - oldVnode 
  • 当响应式数据发生变化时,将会引起组件重新render,此时就会生成新的VDOM-newVnode 
  • 使用oldVnode 与 newVnode 做diff操作,将更改的部分应到真实DOM上,从而转换为最小量dom操作,高效更新视图 

四. 请说一下你对响应式数据的理解?

1.1 核心本质:  

 无论Vue2还是Vue3,响应式的底层原理都遵守"依赖收集+派发更新"机制: 

  1. 数据被访问时,记录"谁"在用这个数据(依赖收集)
  2. 数据被修改时,通知相关逻辑或组件重新执行(派发更新)

Vue2响应式底层原理(基于Object.defineProperty)将属性劫持,数组则是通过重写数组方法来实现,多层对象是通过递归来实现劫持

关键模块

  • Dep 每个属性一个Dep,保存他的依赖(Watcher列表)
  • Watcher  每个使用这个属性的地方(比如组件) 对应一个Watcher 

数据变化触发视图更新的流程: 

组件渲染(访问data) -> getter -> Dep收集当前Watcher 

修改数据 -> setter -> Dep 通知 -> Watcher.run( )  -> 组件重新渲染 

1.2 vue2缺陷和Vue3响应式实现的区别

vue2: 

  1. 在vue2的时候使用defineProperty来进行数据的劫持,需要对属性进行重写添加getter及setter性能差
  2. 当新增属性和删除属性时无法监控变化,需要通过$set,$delete实现
  3. 数组不采用defineProperty 来进行劫持(浪费性能,对所有索引进行劫持会造成性能浪费)需要对数组单独进行处理
  4. 对于es6中新产生的Map,Set这些数据结构不支持 

vue3: 

vue3使用Proxy,可以代理整个对象,能够监听新增,删除属性,且支持更多数据类型(如Map,Set)

五. v-if 和v-shou 

1.渲染方式不同

  • v-if 根据条件决定是否创建或销毁DOM元素,条件为假时元素完全不存在与页面 
  • v-show 元素始终存在,只是通过CSS的display: none来控制显示与隐藏

2.切换性能差异 

  • v-if 频繁切换时性能开销大,因为需要多次创建和销毁DOM  (触发重排和重绘) 重排一定会引起重绘,但重绘不一定会引起重排 
  • v-show只改变样式,切换过程块,性能开销较小 (只触发重绘,不会导致重排,因为布局结构未发生变化 )

3.初始渲染开销

  • v-if 初次条件为假时,不渲染元素,节省初次渲染那性能
  • v-show 无论条件真假,都会渲染元素,初始渲染开销相对较大

4.优先级

  • v-if 优先级高于v-show 

    当同一个元素同时写了v-if 和 v-show 时,Vue会先判断v-if的条件,如果为假,元素根本不会渲染,v-show就不会生效
  • 只有v-if 条件为真时,v-show才会控制元素的显示和隐藏
  • 原因:  v-if 控制的是元素是否存在于DOM, 属于"结构性"条件v-show控制的是元素的css样式,是"表现层"的控制.结构性条件优于表现层控制 

六. computed 和watch 的区别

1.computed 

  • 用于声明式定义一个基于响应式数据的计算属性
  • 特点 : 会缓存计算结果,只有当依赖的数据变化时才重新计算
  • 使用场景: 适合用来做数据的派生计算,避免重复执行昂贵计算. 

const state = reactive({
  count: 1,
  price: 10
})

// 定义计算属性
const total = computed(() => {
  return state.count * state.price
})

// 使用
console.log(total.value)  // 10

// 当 state.count 或 state.price 改变时,total 会自动更新且有缓存
state.count = 2
console.log(total.value)  // 20

2.watch 用法和特点 

  • 作用: 监听响应式数据的变化,并在变化时执行回调函数
  • 特点: 不缓存,数据每次变化都会执行回调
  • 使用场景: 适合处理异步操作,手动执行副作用(如请求接口,操作DOM,触发动画等)
  • 有点: 灵活,可监听多个数据,便于执行复杂逻辑

const state = reactive({
  count: 0
})

// 监听 state.count 变化
watch(() => state.count, (newVal, oldVal) => {
  console.log(`count 从 ${oldVal} 变成了 ${newVal}`)
})

// 支持立即执行
watch(() => state.count, (newVal) => {
  console.log('立即执行,当前 count:', newVal)
}, { immediate: true })

// 支持深度监听
const obj = reactive({ nested: { num: 0 } })
watch(() => obj.nested, (newVal) => {
  console.log('嵌套对象变化:', newVal)
}, { deep: true })

// 监听多个数据
watch([() => state.count, () => obj.nested.num], ([newCount, newNum]) => {
  console.log(`count: ${newCount}, num: ${newNum}`)
})

七. vue3 ref 和reactive 区别

1. ref 

  • 作用: 用于创建一个响应式的基本类型数据引用,也可以包装对象
  • 返回值: 返回一个对象,内部值存放在.value属性上,需要通过.value来访问和修改
  • 使用场景: 适合处理基本类型响应式数据,或者需要将某个值单独包装程序响应式场景
  • 特点: 对基本类型进行相应式处理;通过.value 访问和赋值, 适合配合解构使用,避免相应丢失,底层采用的是Object.defineProperty( ) 实现的  

2.reactive 

  • 将一个普通对象或数组转换为深层响应式代理对象
  • 返回的是被代理的原对象,访问属性时自动相应,无需.value 
  • 适用场景: 适合处理复杂对象,嵌套对象和数组的响应式
  • 特点: 

    1. 适用Proxy 深度代理对象所有属性; 
    2. 解构会导致响应丢失; 
    3. 适合状态管理的大型对象 

八.vue3  watch 和 watchEffect 的区别

1.watch 

显示地监听一个或多个特定的响应式数据源,当其发生变化时执行回调函数

特点:

  •  明确监听目标(如ref,reactive的某个属性,getter函数等)
  • 回调函数有新值和旧值两个参数 
  • 支持deep深度监听和immediate 立即执行
  • 更适合处理复活用逻辑,异步请求等 

适用场景: 

  • 某个具体数据变化时执行逻辑(如发请求,更新状态)
  • 需要用到新旧值对比
  • 需要手动监听某个计算属性或getter的结果

2.watchEffect 

作用:  自动收集副作用用到的所有响应式数据,这些依赖变化时就重新执行回调.

特点:  

  • 不需要指定监听的目标,自动追踪依赖
  • 第一次立即执行(类似immediate:true)
  • 依赖变化时自动重新运行副作用函数
  • 支持副作用清理

九. vue的生命周期

1.Vue2的生命周期 

  • beforeCreate  实例初始化完成前,data和methods都还未挂载(创建前)
  • created 实例已创建完成,可访问data,methods,computed (创建后)
    用途:
    1. 请求接口获取数据  适合发起不依赖DOM的请求
    2. 初始化定时器
    3. 事件总线监听
  • beforeMount 模版已编译,尚未挂在到DOM (挂在前)
  • mounted 模版已挂在到真实DOM,适合操作DOM,请求数据(挂载后)
    1. 操作DOM (如图标库初始化)
    2. 获取DOM节点尺寸
    3. 请求数据(如果需要操作DOM结构) 
  • beforeUpdate 响应式数据更新前调用,适合更新前的逻辑处理 (更新前)
    1. 对更新前的旧数据做处理
    2. 手动保存滚动位置等
  • updated 响应式数据更新后,DOM已重新渲染完成(更新后)
    1. 获取最新DOM状态
    2. 使用$nextTick 做动画,滚动条调整等
  • beforeDestroy 实例销毁前调用,可以一座清理操作(销毁前)
    1. 清除定时器
    2. 解绑事件监听
    3. 清理全局状态
  • destyoyed 实例销毁后调用,所有事件监听器,子组件等已清理

2.Vue3 生命周期(组合式API)

Vue3 中推荐使用组合式API,声明周期名称以on开头(在setup()中调用):

Vue2 Options APIVue3 Composition API
beforeCreate⛔(已废弃)
created⛔(已废弃)
beforeMountonBeforeMount()
mountedonMounted()
beforeUpdateonBeforeUpdate()
updatedonUpdated()
beforeDestroyonBeforeUnmount()
destroyedonUnmounted()
——onActivated() / onDeactivated()(keep-alive 用)
——onErrorCaptured()(捕获子组件错误)

十. Vue中key的作用和原理

1. 唯一表示VNode 

  • key的本质是: 为每一个虚拟DOM节点设置唯一的标识 

  • 帮助Vue准确判断哪些节点需要服用,哪些需要新增或删除

2.提高DIff算法效率

  • 没有key时,Vue默认会用"就地复用策略",会造成错误复用,渲染错误,动画异常等问题
  • 有key后,Vue会根据key精准对比新旧节点,提高性能和准确性 

3.对比规则: 

1. 旧虚拟DOM中找到了与新虚拟DOM相同的key: 

  • 若虚拟DOM中内容没变,直接使用之前的真实DOM!
  • 若虚拟DOm中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM 

2.旧虚拟DOM中未找到与新虚拟DOM相同的key 

  • 创建新的真实DOM,随后渲染到页面

3. 用index作为key可能会引发的问题: 

1. 若对数据进行: 逆序添加,逆序删除等破坏顺序操作:

会产生没有必要的真实DOM更新==> 界面效果没问题,但效率低

2. 如果结构中还包含输入类的DOM: 

会产生错误DOM更新===> 界面有问题 

4.开发中如何选择key?: 

1. 最好使用每天数据的唯一表示为key,比如id,手机号,身份证号,学号等唯一值

2. 如果不存在对数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的

十一. 自定义指令

1.本质: 

  • Vue自定义指令其实是对原生DOM操作的封装
  • 指令钩子函数会接受到当前绑定的DOM元素el,通过操作它实现各种效果 
  • 本质上,Vue在编译模版时,会解析指令,调用对应的钩子函数完成操作 

2.指令钩子参数详解

(el: HTMLElement, binding: DirectiveBinding, vnode: VNode, prevVnode: VNode | null) => void

  • el : 指令绑定的真实DOM元素
  • binding: 一个对象,包含指令相关信息

    binding.value: 绑定的值

    binding.oldValue: 绑定的旧值(只有更新和卸载时有)

    binding.arg:指令传入的参数,如v-my-directive: arg中的arg 

    binding.modifiers:修饰符对象,如v-my-directive.foo.bar变成{foo:true,bar:true}
  • vnode: 当前虚拟节点
  • prevVnode :上一个虚拟节点 

3.应用场景: 

1.权限控制 

  • 根据用户权限,控制元素的显示或隐藏
  • 适合按钮,菜单等权限校验

app.directive('permission', {
  mounted(el, binding) {
    const userRole = getUserRole();
    if (!userRole.includes(binding.value)) {
      el.style.display = 'none';
    }
  }
});

2.懒加载与无限滚动

  • 监听滚动事件,实现图片懒加载或列表滚动到底部自动加载更多
  • 性能优化必备手段

十二. 说说你对nextTick的理解?

1. 概念 

Vue中视图更新是异步的,使用nextTick方法可以保证用户定义的逻辑在更新之后执行

可用于获取更新后的DOM,多次调用nextTick会被合并

因为: Vue在修改响应式数据后,不会立即更新DOM,而是先缓存修改,然后等同步代码跑完后,再一次性批量更新DOM,nextTick就是告诉Vue: 

在你DOM渲染完之后通知我,我再执行我的逻辑 

2.使用场景

场景为什么用 nextTick
修改数据后需要立即获取 DOM数据变了,但 DOM 还没更新,需等 DOM 更新后操作
组件生命周期内要访问更新后的 DOM如在 mounted 里等待某些异步 DOM 生成
手动聚焦某个输入框改变可见性后,DOM 不一定立即出现
UI 动画或过渡计算依赖 DOM等 DOM 完整渲染后再做动画更安全

十三. 讲一下keep-alive 

keep-alive用于缓存组件实例,当组件切换时被缓存的组件不会被销毁,下次再激活时可以继续使用之前的状态,提升性能

1.解决了什么问题? 

默认情况下,Vue的组件在切换时会销毁卸载,再重新挂载创建,比如常见的tab切换或动态组件切换时

但有些组件,比如: 

  • 表单页面
  • 复杂表格
  • 需要保留滚动/编辑状态的页面

频繁销毁和重建,会造成性能浪费和用户体验下降,keep-alive就是用来解决这个问题的。

2. 工作原理  

被keep-alive包裹的组件会被Vue缓存下来,切换时不是销毁,而是隐藏,再次激活时是显示

<template>
  <keep-alive>
    <component :is="currentView" />
  </keep-alive>
</template>

<script setup>
import FormPage from './FormPage.vue';
import ListPage from './ListPage.vue';
import { ref } from 'vue';

const currentView = ref('ListPage');
</script>

 上面这个例子中,当currentView切换时,之前的组件不会被销毁 

3.keep-alive的常用属性

<keep-alive include="FormPage,ChartPage" exclude="LoginPage" max="10">

  • include  只缓存哪些组件(名字)

  • exclude 排除哪些组件不缓存
  • max 最多缓存多少个组件实例,超出会LRU置换

注意: 这些名字必须是组件的name选项 

生命周期钩子: 

当组件被缓存时不会触发created和mouned,而是: 

  • activated():被显示时触发
  • deactiveted( ) :被隐藏时触发 

export default {
  name: 'MyForm',
  activated() {
    console.log('组件被激活');
  },
  deactivated() {
    console.log('组件被缓存');
  }
}

十四. Vue中使用了哪些设计模式?

1.观察者模式

 对象之间一对多依赖,一个对象状态变化,所有依赖它的对象都会收到通知

Vue中应用: 

  • Vue的响应式系统(如data,ref,reeactive)
  • watch,computed 底层原理

2.发布-订阅模式(Pub-Sub Pattern)

 发布者和订阅者之间不直接通信,通过事件中心解耦

Vue中应用: 

  • 组件间通信(如EventBus)
  • Vue内部事件机制(如$meit/$on)

3.策略模式

指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案

4. 装饰器模式

在不改变原类的情况下,动态扩展其功能

Vue中的应用: 

  • Vue3中Composition API的reactive,ref 
  • @Watch @Component 等装饰器 

5. 代理模式 

通过代理对象控制对目标对象的访问 

Vue中应用: 

  • Vue3响应式系统的核心Proxy
  • 拦截属性的get/set,实现依赖收集和派发 

6.单例模式

定义:全局只有一个实例

Vue中应用: 

  • Vuex 状态管理(store 是全局唯一)
  • Vue根实例 

7.组合模式 

将对象组合成树形结构表示"部分-整体"的层次结构

Vue中应用: 

  • 组件树结构(父组件,子组件递归组合)
  • 插槽(slot) / 嵌套组件渲染

总结: Vue中大量使用了设计模式,比如响应式原理中用到观察者模式和代理模式,组件通信中用到发布-订阅模式,Vue3用Proxy 重写响应式就是代理模式的体现,像Vuex是一个典型的单例模式,组件树结构式组合模式,而Vue的表单校验,diff算法中也使用了策略模式,这些设计模式提升了Vue的扩展性和可维护性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值