v-model 是如何实现的?本质是什么?
v-model 本质是v-bind+v-on的语法糖,用于实现数据和视图之间的双向绑定;在组件上本质是通过 prop + $emit 实现的父子通信语法糖。Vue2 默认使用 value 和 input,Vue3 改为 modelValue 和 update:modelValue。
v-model 可以被用在自定义组件上吗?如果可以,如何使用?
v-model 可以用于自定义组件。
在 Vue2 中本质是 value + input 事件的语法糖;
在 Vue3 中本质是 modelValue + update:modelValue 的语法糖。
其核心机制都是通过 prop 传值、通过 $emit 通知父组件,实现父子组件之间的双向数据绑定。
data为什么是一个函数而不是对象?
因为组件是可复用的,会被创建多个实例,如果 data 是对象,所有实例会共享同一个数据对象,导致数据互相污染;使用函数可以为每个组件实例返回一个全新的数据对象,保证状态独立。根实例只有一个,不存在复用问题,因此可以使用对象。
对keep-alive的理解,它是如何实现的,具体缓存的是什么?
keep-alive 是 Vue 内置的抽象组件,用来缓存动态组件或 router-view 中的组件实例,避免组件重复创建和销毁。
它通过缓存组件的 vnode 和 componentInstance,在组件切换时不销毁实例,而是保存状态,下次激活时直接复用。
内部使用 LRU 策略控制缓存数量,可以通过 include、exclude、max 控制缓存规则。
$nextTick 原理及作用
1.$nextTick 的作用
$nextTick 用于在DOM 更新完成之后 执行回调。因为 Vue 的 DOM 更新是异步批量更新的,所以数据变化后,DOM 不会立刻更新,而是等本轮事件循环结束后统一更新。
2.核心原理
nextTick 本质上是利用 JavaScript 的 EventLoop 机制,优先使用 Promise.then 创建微任务,在 DOM patch 完成后执行回调。常用于在数据更新后获取最新 DOM 结构或操作 DOM。
Vue 中给 data 中的对象属性添加一个新的属性时会发生什么?如何解决?
在 Vue2 中,data 对象的属性在实例创建时就被转换为响应式属性。如果动态给对象添加新属性,Vue 无法检测到变化,视图不会更新。解决方法是使用 this.$set(obj, 'newProp', value) 或 Vue.set(obj, 'newProp', value) 来手动将新属性转换为响应式。Vue3 则使用 Proxy,可以自动响应对象属性的新增。
Vue中封装的数组方法有哪些,其如何实现页面更新
在 Vue2 中,由于 Object.defineProperty不能监听数组索引和长度变化,Vue对数组的方法(push、pop、shift、unshift、splice、sort、reverse)进行了封装。每个方法执行时,先调用原生数组操作,然后对新增元素执行响应式处理,最后通过 dep.notify() 通知 watcher 更新页面,实现视图的实时刷新。Vue3 使用 Proxy 后,无需重写数组方法,所有数组变化都可以被拦截。
Vue 单页应用与多页应用的区别
| 类型 | 全称 | 页面加载方式 | 资源加载 | 页面切换 |
|---|---|---|---|---|
| SPA | Single Page Application | 只加载一次主页面 | JS/CSS 等资源只需初次加载 | 切换组件,局部刷新,无整页刷新 |
| MPA | Multi Page Application | 每次访问新页面都加载新页面 | 每个页面都需加载对应 JS/CSS | 页面整体刷新 |
| 方面 | SPA | MPA |
|---|---|---|
| 页面结构 | 单个 HTML 页面 + 前端路由 | 多个 HTML 页面,每个页面独立 |
| 路由方式 | 前端路由(Vue Router)控制组件显示 | 后端路由,页面跳转由服务器返回 HTML |
| 用户体验 | 页面切换流畅,无白屏闪烁 | 页面切换会整体刷新,有明显闪烁 |
| 性能 | 初次加载大,后续切换快 | 每次加载页面都需要请求资源,切换慢 |
| SEO 优势 | SEO 不友好(需要 SSR 或 prerender) | SEO 友好,页面内容直接渲染在 HTML |
| 开发方式 | 前端主导,组件化开发,API 数据交互 | 后端主导,每个页面独立开发,逻辑耦合后端 |
| 缓存和状态 | 前端维护状态,数据可缓存 | 页面刷新后状态丢失,需要后端保存 |
Vue data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染吗?
Vue 响应式系统侦测到数据变化后,并不会立即操作 DOM,而是把变化的 watcher 推入异步更新队列,队列中同一 watcher 多次变化会去重,然后在下一个事件循环 tick 中统一执行 DOM 更新。可以使用 this.$nextTick 在 DOM 更新后执行操作。
简述 mixin、extends 的覆盖逻辑
Mixin 是 Vue 提供的可复用组件逻辑机制,通过将生命周期、方法、数据等混入组件,实现代码复用;组件自己的同名选项会覆盖 mixin 的选项,生命周期钩子会先执行 mixin 的,再执行组件自身的。
mixin 和 extends 本质都是通过 mergeOptions 进行选项合并。
合并顺序是 extends → mixins → 组件自身。
生命周期钩子会合并成数组,并按顺序执行;
data 会执行函数后合并对象,冲突时组件优先;
methods、computed、props 等选项会直接覆盖,组件优先级最高;
watch 如果重名会合并成数组。
描述下Vue自定义指令
Vue 自定义指令是对普通 DOM 元素进行底层操作的扩展机制,适用于需要直接操作 DOM 的场景,比如自动聚焦、图片懒加载、滚动监听或集成第三方插件。
自定义指令可以全局注册,也可以在组件中局部注册。
在 Vue2 中,指令包含 bind、inserted、update、componentUpdated、unbind 等生命周期钩子,可以在不同阶段对元素进行操作。钩子函数会接收 el、binding、vnode 等参数。
一般建议自定义指令只用于操作 DOM,而不要直接修改组件内部数据。
子组件可以直接改变父组件的数据吗?
子组件不能直接修改父组件传递过来的数据(props)。
Vue 采用的是单向数据流 ,数据只能从父组件流向子组件。如果子组件直接修改 props,Vue 会在控制台给出警告。这样设计是为了保证数据流清晰,避免组件之间状态混乱,方便维护和调试。如果子组件需要修改父组件的数据,应该通过 $emit 触发一个自定义事件,由父组件在事件回调中修改数据。
对 React 和 Vue 的理解,它们的异同
React 和 Vue 都是用于构建用户界面的前端框架,核心思想都是组件化和数据驱动视图,并且都使用 Virtual DOM 来提高渲染性能。它们的核心库都只关注视图层,路由、状态管理等功能通过生态库扩展,属于"核心精简、生态完善"的设计思路。
| 对比维度 | Vue | React |
|---|---|---|
| 设计思想 | 偏声明式 + 响应式 | 偏函数式编程 |
| 数据流 | 单向数据流(支持 v-model 语法糖) | 单向数据流 |
| 响应式原理 | Vue2:Object.definePropertyVue3:Proxy 精准依赖收集 | 状态变化后组件重新执行,通过 diff 比较 Virtual DOM |
| 更新机制 | 依赖追踪,细粒度更新 | 组件重新 render,再做 Virtual DOM diff |
| 模板写法 | Template 模板,接近 HTML | JSX,本质是 JavaScript |
| 逻辑复用方式 | Vue2:mixinVue3:Composition API | HOC、Hooks |
| 性能优化方式 | 默认做依赖追踪优化 | 需要手动优化(memo、useMemo、useCallback) |
assets和static的区别
在 Vue CLI 项目中,assets和static都是用来存放静态资源的,比如图片、字体、样式文件等。
| 对比项 | assets | static |
|---|---|---|
| 是否参与打包 | 会被 webpack 处理 | 不会被 webpack 处理 |
| 是否压缩/优化 | 会压缩、hash命名、转 base64 | 原样拷贝 |
| 引用方式 | 通过 import 或 require | 通过绝对路径访问 |
| 缓存策略 | 文件名带 hash,利于缓存控制 | 文件名固定 |
| 适用场景 | 需要参与构建的资源 | 不需要处理的资源 |
delete和Vue.delete删除数组的区别
| 方法 | 对数组的影响 | 对视图更新 |
|---|---|---|
delete arr[index] |
只是把对应索引置为 undefined,数组长度不变,索引不改变 |
不会触发 Vue 视图更新 |
Vue.delete(arr, index) 或 arr.splice(index,1) |
删除指定索引的元素,数组长度减 1,后面的元素索引自动前移 | 会触发 Vue 视图更新 |
vue如何监听对象或者数组某个属性的变化
Vue2 监听对象或数组属性变化,新增属性要用 this.$set,数组修改要用重写的数组方法(如 splice、push,Vue 对数组原型方法做了拦截,执行这些方法时会触发依赖更新(dep.notify()),视图自动刷新),这样才能触发响应式更新。
对SSR的理解
SSR 就是服务端渲染 ,它把 Vue 组件在客户端渲染成 HTML 的工作放到服务端去完成,然后把生成好的完整 HTML 页面直接返回给浏览器。
优势
SEO 更友好:搜索引擎爬虫可以直接抓取完整的 HTML 内容,而不依赖 JavaScript 执行。
首屏渲染更快:浏览器可以立即显示页面内容,提升用户体验,尤其是移动端或网络较慢的情况下。
缺点
生命周期限制:服务器端没有 DOM,只有 beforeCreate 和 created 钩子可用,不能操作 mounted 或直接访问 DOM。
外部库限制:某些依赖浏览器 API 的第三方库需要特殊处理或不能直接使用。
服务端压力增加:每次请求都需要服务器渲染页面,增加了服务器负载和开发复杂度。
Vue的性能优化有哪些
编码阶段。我们尽量减少 data 中的数据量,因为每个属性都会被 Vue 劫持收集 watcher,数据越多渲染开销越大。列表渲染时,要避免 v-if 和 v-for 连用,长列表可以结合虚拟滚动或者懒加载。组件切换时,可以用 keep-alive 缓存不活跃组件,减少重复渲染。事件绑定可以用事件代理,路由组件可以用懒加载或异步组件,此外防抖节流和图片懒加载也是常用手段。
SEO 优化。Vue 的预渲染或者服务端渲染 SSR 可以让首屏更快,同时改善搜索引擎抓取。
打包优化。生产环境可以压缩代码、使用 Tree Shaking 去掉无用代码,利用 CDN 加载第三方库,抽离公共文件,提高缓存利用率,多线程打包提升构建速度。
用户体验优化。可以做骨架屏、PWA、缓存策略和开启服务端 Gzip 压缩,让页面加载更快、体验更顺畅。
v-if 和 v-for哪个优先级更高?如果同时出现,应如何优化?
在 Vue 中,v-for 的优先级高于 v-if。也就是说,如果同时出现在一个节点上,Vue 会先执行循环生成每一项,再对每一项执行 v-if 条件判断。这会导致即使很多项最终不渲染,循环也已经执行了,浪费性能。
如果条件是针对整个列表的,可以把 v-if 放在外层,用一个 <template> 包裹,先判断条件再执行 v-for 循环。
如果条件是针对单个循环项的,最好用计算属性提前过滤掉不需要显示的元素,让循环只遍历需要渲染的项。