前端面试题(仅供自己记录)

352 阅读27分钟

目录


目录


一、基础类

1. Vue2 和 Vue3 响应式的区别?

  • Vue 2: 基于 Object.defineProperty,在初始化时需要递归遍历所有属性,无法监听属性的新增和删除,对数组的修改需要重写原型方法。
  • Vue 3: 基于 Proxy (ES6),通过代理整个对象拦截所有操作(包括增删),支持懒代理,性能更优,解决了 Vue 2 的诸多限制。

2. Vue3 中 Composition API 相比 Options API 的优势?

  • 逻辑组织: 解决了 Options API 中逻辑分散的问题,允许将同一功能相关的代码(数据、方法、计算属性)聚合在一起,提高可读性和维护性。
  • 逻辑复用: 替代了 Mixins,通过 Composable 函数(Hooks)实现更灵活、无命名冲突、数据来源清晰的代码复用。
  • 类型推导: 与 TypeScript 结合更自然,类型推导更准确。
  • 性能: 导出的函数利于打包工具进行 Tree-shaking,减小产物包体积。

3. Vue3 中的 Teleport 有什么作用?

Teleport 是一个内置组件,作用是 将组件的内容渲染到 DOM 树中指定的其他位置。它常用于模态框、通知、提示框等场景,解决 z-indexoverflow: hidden 等父组件样式导致的显示问题。

4. css优化技巧

  • 合理使用选择器
  • 减少DOM操作,减少重绘和重排
  • 去除无效的选择器
  • 文件压缩
  • 异步加载文件
  • 减少@import的使用

5. Vue3 中 ref 和 reactive 的区别?

特性refreactive
接收参数任何类型(原始类型或对象)仅限对象类型
访问/修改必须通过 .value直接访问属性
底层实现内部包含一个值,如果值为对象则会调用 reactive使用 Proxy 对对象进行深度代理
模板使用自动解包(无需 .value直接使用

6. Vue 中 keep-alive 的实现原理?

keep-alive 是一个内置组件,通过在内部维护一个 缓存对象 和一个 Key 列表 来实现组件实例的缓存。当组件切换时:

  1. 检查缓存,如果命中,直接复用已有的组件实例(不重新执行 created/mounted)。
  2. 如果没有命中,则创建新实例并将其存储在缓存中。
  3. 如果缓存数量达到 max,则使用 LRU(最近最少使用) 策略淘汰最旧的组件。

7. Vue 中 diff 算法的优化点?

Vue 的 diff 算法基于同层比较和启发式策略优化性能。

  1. 同层比较: 只比较同一层级的节点,将复杂度从 O(n³) 降至 O(n)。
  2. 双端比较 (Vue 2): 引入四个指针(新旧头尾),通过快速比较头尾节点,高效处理列表的头尾增删或反转。
  3. 最长递增子序列 (LIS) (Vue 3): 在处理乱序列表时,计算 LIS 以找到无需移动的节点,最大限度减少 DOM 移动操作,性能更优。
  4. Key 的重要性: 通过 key 确保 VNode 的唯一身份,从而实现高效复用和节点移动。

8. Nuxt 3 的混合渲染模式 (Hybrid Rendering) 是什么?请举例说明其应用场景。

混合渲染允许在 同一个 Nuxt 应用中,为不同的路由配置不同的渲染策略。

  • 策略包括: SSR(动态服务端渲染)、SSG(构建时静态生成)、CSR(客户端渲染)和 ISG(增量静态生成)。
  • 应用场景:
    • 首页/文档: 使用 SSG 获得最高性能和 SEO。
    • 用户中心/购物车: 使用 CSRSSR 以确保实时性和个性化。
    • 博客/商品详情页: 使用 ISG 兼顾性能和数据新鲜度。

9. Vue3 中的 Tree-shaking 是如何实现的?

Vue 3 的 Tree-shaking 并非 Vue 自身实现,而是通过 ES Modules (ESM) 的静态特性函数化 API 设计 实现:

  1. ESM 静态分析: Vue 3 核心功能都是通过 import { ref, computed } 导入的,打包工具(如 Rollup/Vite)可以静态分析出哪些函数被使用了。
  2. 函数化设计: 几乎所有功能都作为独立函数导出,相比 Vue 2 挂载在 this 上的动态属性,Vue 3 的模块化设计更容易被摇树算法识别和移除未使用代码,从而减小最终包体积。

10. Vue 中 computed 的实现原理?

计算属性的核心是 惰性求值 (Lazy Evaluation)缓存 (Caching)

  1. Watcher 机制: 每个计算属性都对应一个 Computed Watcher,该 Watcher 默认是惰性 (lazy: true)。
  2. 依赖收集: 首次访问时,Watcher 执行计算函数,收集其依赖(如 refreactive)。
  3. 缓存: 结果被缓存,并设置 dirty 标志为 false
  4. 依赖变化: 当依赖变化时,Watcher 收到通知,只将 dirty 标志设为 true不立即重新计算
  5. 重新求值: 只有当计算属性再次被访问时,因为它发现 dirtytrue,才会重新执行计算函数,更新缓存,并重置 dirty 标志。如果 dirtyfalse,则直接返回缓存结果。

11. Vite 和 webpack 区别

特性ViteWebpack
核心原理基于浏览器原生 ESM,开发时无需打包,按需加载。基于打包 (Bundling),将所有模块打包成 bundle 文件。
启动速度极快(毫秒/秒级)。较慢(随着项目增大而变慢)。
HMR 速度极快,HMR 仅针对修改的文件,与项目规模无关。相对较慢,需要重新打包部分模块。
生产构建使用 Rollup,专注于 Tree-shaking 和优化。使用自身打包器,生态成熟,功能强大。

12. Vue2 中的 nextTick 原理?

nextTick 的作用是延迟回调函数到 下一次 DOM 更新循环之后 执行。

  • 原因: Vue 的 DOM 更新是异步的,将数据变更缓冲在一个队列中。
  • 原理: nextTick 利用 JavaScript 的 事件循环 机制,将回调函数推入到 微任务队列 中(优先使用 Promise.thenMutationObserver,降级使用宏任务 setTimeout(fn, 0))。
  • Vue 在当前事件循环的同步代码执行完毕后,会清空微任务队列,Vue 的 DOM 更新任务在此时执行,nextTick 的回调紧随其后,从而保证了回调执行时 DOM 已经是最新的状态。

二、原理类

13. 如何封装一个带有自动请求和销毁逻辑的 useFetch Hook?

  1. 响应式状态: 使用 refshallowRef 定义 data, error, isLoading 状态。
  2. 请求封装: 封装数据获取函数 fetchData
  3. 自动取消:fetchData 中使用 AbortController 发出请求,并在 onUnmounted 钩子中调用 controller.abort(),以确保组件销毁时能自动取消未完成的请求,防止内存泄漏。
  4. 自动执行:setup 函数中立即调用 fetchData 来发起请求。
  5. 返回值: 返回包含所有状态和手动刷新函数 refresh 的对象。

14. Nuxt3 的 SSR 渲染流程?

  1. 服务器接收请求: Nitro 引擎接收到请求,创建一个新的 Vue 独立实例(避免状态污染)。
  2. 数据预取: 执行页面组件中的 useAsyncData/useFetch 等服务端数据获取逻辑,等待数据就绪。
  3. 渲染 HTML: 使用 Vue 的 SSR 渲染器将带数据的 Vue 实例渲染成完整的 HTML 字符串。
  4. 序列化状态: 将预取到的数据状态序列化并注入到 HTML 的 <script> 标签中 (window.__NUXT__)。
  5. 发送响应: 服务器将完整的 HTML 响应发送给浏览器。
  6. 客户端激活 (Hydration): 浏览器下载 JS,读取序列化状态,并用客户端 Vue 实例接管和“激活”已有的静态 DOM,附加事件监听器,使页面成为一个功能完整的 SPA。

15. Vue Router4 中的路由懒加载如何实现?

通过使用 ES6 动态 import() 语法实现。

在路由配置中,将组件定义为一个返回 import() 的函数:

{ 
  path: '/about', 
  component: () => import('../views/About.vue') 
}

构建工具(Webpack/Vite)会识别 import() 作为代码分割点,将对应的组件及其依赖打包成一个独立的 chunk,只有当路由被访问时才异步加载该文件。

16. 在大型 Vue 3 项目中,你是如何进行状态管理的?

通常采用 组合策略

  1. Pinia: 作为 全局状态管理的首选。它类型安全、API 简洁、支持模块化和 Tree-shaking,适用于管理用户认证、全局配置等核心状态。
  2. Composable Functions (Hooks): 适用于 逻辑复用和模块级状态。用于封装 useFetch, useMousePosition 等可复用的有状态逻辑。也可以用于轻量级的全局状态共享。
  3. Provide/Inject: 适用于 特定组件树内的通信,解决 Prop 逐层传递(Props Drilling)问题,多用于组件库或复杂的局部表单结构。

17. Vue3 是如何支持 TypeScript 的?TypeScript中的接口是什么?如何定义和使用接口

Vue 3 将 TypeScript 作为一等公民。

  1. 源码使用 TS 重写: 提供了准确、完整的类型定义文件。
  2. Composition API 的天然优势: 函数式的 API 易于类型推导。
  3. 类型安全的 API: 使用 defineProps<T>defineEmitsref<T> 等泛型 API,提供了编译时的类型检查。
  4. Volar 语言工具: 提供了对 SFC (.vue 文件) 中模板和脚本的深度类型支持。

接口是一种用于定义对象的结构和类型的语法。可以使用interface关键字来定义接口。

18. 微前端架构中子应用的隔离原理?

隔离主要体现在三个方面:

  1. CSS 隔离: 使用 Shadow DOM(硬隔离)或 Scoped CSS/CSS Modules(软隔离)来避免样式冲突。
  2. JavaScript 隔离 (JS 沙箱): 主要通过 Proxy 代理沙箱 来实现。它为每个子应用创建一个代理的 window 对象,所有对全局变量的修改都发生在代理对象上,从而防止全局变量污染和冲突。
  3. DOM 隔离: 通过约定每个子应用渲染到独立的容器中,并对 document.querySelector 等 API 进行劫持,将查找范围限定在子应用的容器内。

19. 请说出三种减少页面加载时间的方法。(加载时间指感知的时间或者实际加载时间)

  • 优化图片
  • 图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方)
  • 优化CSS(压缩合并css,如margin-top,margin-left...)
  • 网址后加斜杠(如www.campr.com/目录,会判断这个“目录是什么文件类型,或者是目录。)
  • 标明高度和宽度(如果浏览器没有找到这两个参数,它需要一边下载图片一边计算大小,如果图片很多,浏览器需要不断地调整页面。这不但影响速度,也影响浏览体验。当浏览器知道了高度和宽度参数后,即使图片暂时无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载时间快了,浏览体验也更好了。)
  • 减少http请求(合并文件,合并图片)。

20. HTTP/2 相比 HTTP/1.1 的核心优势是什么?

  1. 二进制分帧: 将请求和响应拆分为二进制帧,解析更高效。
  2. 多路复用 (Multiplexing): 允许在 单个 TCP 连接 上同时传输多个请求和响应,彻底解决了 HTTP/1.1 的 队头阻塞 问题。
  3. 头部压缩 (HPACK): 使用字典和霍夫曼编码压缩 HTTP 头部信息,减少传输开销。
  4. 服务器推送 (Server Push): 服务器可以在客户端请求之前主动推送所需资源,减少往返时间。

21. 如何理解响应式网站?

响应式网站设计 (RWD) 是一种理念:使用一套 HTML 和 CSS 代码,使网站布局能够自动适应和优化在各种不同屏幕尺寸(PC、平板、手机)上的显示效果。

核心技术包括:

  1. 流式布局: 使用百分比、vw 等相对单位。
  2. 媒体查询 (Media Queries): 根据视口宽度设置不同的断点来应用不同的布局样式。
  3. 弹性图片: 使用 max-width: 100% 确保图片不会溢出容器。

三、场景题

22. 如何优化 Vue 中上万条列表渲染?

核心思想是 只渲染用户可见的部分

  1. 虚拟列表 / 虚拟滚动 (Virtual Scrolling): 最优解。通过计算只渲染视口内及其缓冲区内的列表项,并使用占位元素维持滚动条的整体高度。
  2. 时间分片 (Time Slicing): 如果不采用虚拟滚动,可将数据分批次渲染(如每帧渲染 50 条),利用 requestAnimationFrame 避免阻塞主线程。
  3. 分页: 将数据分为多页展示,减少单次渲染量。

23. 如何优化 Vue 项目中的首屏加载速度?

  1. 减少包体积: 路由懒加载、组件按需引入、Tree-shaking、移除无用代码、使用包分析工具。
  2. 优化资源加载: 图片压缩、使用 WebP 格式、开启 Gzip/Brotli 压缩、使用 CDN。
  3. 渲染策略优化: 采用 SSR/SSG预渲染,以加快内容渲染;使用 骨架屏 优化用户感知体验。
  4. 浏览器缓存: 配置 HTTP 缓存头,利用 Service Worker 或设置合适的 Cache-Control

24. Vue 中频繁触发的输入框校验如何优化?

主要使用 防抖 (Debounce) 技术。

  • 防抖: 在事件触发后延迟执行回调,如果在延迟时间内事件再次触发,则重新计时。
  • 适用场景: 用户在连续输入时,只在用户停止输入后,执行一次校验或 API 请求。
  • 实现: 可使用自定义 Composable(如 useDebouncedRef)或 Lodash 等工具库的 debounce 函数。

25. Nuxt 项目如何实现 SEO 优化?

Nuxt 默认的 SSR/SSG 是基础。在此之上,核心在于元数据管理:

  1. 动态元数据: 在页面组件中使用 useHead Composable 动态设置页面的 title, description, og:image 等元标签。
  2. 结构化数据: 嵌入 JSON-LD 格式的 Schema.org 结构化数据,帮助搜索引擎理解内容(如产品、文章)。
  3. 工具链: 使用 Nuxt 模块生成 Sitemap (sitemap.xml)robots.txt
  4. 语义化 HTML: 确保使用正确的 HTML5 标签和清晰的标题层级 (<h1>-<h6>)。

26. 微前端中如何实现跨子应用的状态共享?

  1. 共同的状态管理库 (Pinia/Redux): 最推荐的方案。 由主应用初始化一个 Store 实例,并将其传递给子应用。所有应用共享这个实例。
  2. 主应用下发 Props: 通过微前端框架的 API,主应用将共享数据作为 Props 传递给子应用。
  3. Module Federation (模块联邦): 允许一个应用暴露 Store 或状态函数,其他应用运行时按需加载,实现去中心化的共享。
  4. 浏览器原生通信: 使用 CustomEventpostMessage 实现基于发布-订阅的通信(适合少量简单数据)。

27. Three.js用过吗? 大模型渲染如何优化?

  1. 模型资产优化:
    • 减面: 减少模型多边形数量。
    • LOD (Level of Detail): 根据距离动态切换高、中、低精度模型。
    • 压缩: 使用 Draco 压缩几何体,使用 KTX2 压缩纹理。
  2. 减少 Draw Call:
    • 合并几何体: 将相同材质的小物体合并为单个 Mesh。
    • 实例化渲染: 对大量重复物体使用 InstancedMesh
  3. 渲染策略: 确保开启 视锥剔除;合理使用阴影;如果场景静止,使用 按需渲染(只在必要时调用 renderer.render())。
  4. 资源管理: 及时调用 dispose() 释放几何体、材质和纹理占用的 GPU 显存。

28. 前端会有哪些安全问题,什么场景出现,如何预防

安全问题场景预防措施
XSS (跨站脚本攻击)评论区、URL 参数注入恶意 JS 脚本。输入过滤和输出转义;使用 CSP (Content Security Policy) 限制脚本来源;谨慎使用 v-html
CSRF (跨站请求伪造)诱导用户点击恶意链接,冒用身份发起请求。Anti-CSRF Token;验证 Referer;设置 SameSite=Strict Cookie
中间人攻击 (MITM)在公共网络拦截并窃听/篡改通信。全站启用 HTTPS;配置 HSTS。
点击劫持透明 <iframe> 覆盖在敏感操作按钮上。设置 X-Frame-Options: DENY 响应头。

29. SSR 中如何避免状态污染?

状态污染是由于多用户请求共享服务器上的单例状态导致的。

  • 解决方案: 核心是 为每一次独立的请求创建一个全新的、隔离的状态实例
  • 实践: 必须使用 工厂函数 模式来创建 Vue 实例、Router 实例和 Pinia/Vuex Store 实例。确保 Pinia Store 的 state 必须是一个 返回新对象的函数,以保证每次请求的状态都是独立的。

30. Vue 项目中如何解决组件通信复杂的问题?

  1. 父子通信: 优先使用 Props$emit,保持单向数据流。
  2. 跨层级通信: 使用 Provide / Inject 解决 Prop 逐层传递问题。
  3. 任意组件通信:
    • 状态管理库 (Pinia / Vuex): 首选方案。将全局或跨模块状态集中管理,实现组件间的解耦和清晰的数据流。
    • Composable Functions: 适用于模块级的、轻量级的状态共享。
    • (避免使用 Event Bus)

31. 微前端如何处理公共依赖重复打包的问题?

核心是实现 依赖共享

  1. Module Federation (模块联邦): 最推荐的方案。 使用 Webpack 5 的 shared 配置,允许在不同应用间运行时共享单例依赖,并智能处理版本兼容。
  2. externals + CDN: 传统方案。将 Vue、React 等库通过 CDN 全局引入,子应用在构建时将这些库配置为 externals,不进行打包。
  3. 公共组件库 npm 包: 虽然解决了代码复用,但如果不配合模块联邦,仍可能存在重复下载依赖的问题。

32. qiankun如何实现JS沙箱?

qiankun 主要使用两种沙箱:

  1. 快照沙箱 (SnapshotSandbox): 兼容方案。在子应用激活前记录 window 状态快照,在失活时恢复状态。不支持多实例共存。
  2. 代理沙箱 (ProxySandbox): 主流方案。利用 Proxy 为每个子应用创建一个“假的” window 代理对象。读操作穿透到真实 window,写操作只发生在代理对象上,从而实现多实例共存下的隔离。

33. Vue 项目如何减少包体积?

  1. 代码分割: 路由懒加载、异步组件 (defineAsyncComponent)。
  2. 按需引入: 使用插件(如 unplugin-vue-components)或手动按需引入 UI 库和工具库。
  3. Tree-shaking: 确保使用 ESM 语法,并配置构建工具移除死代码。
  4. 资源优化: 图片压缩、字体文件裁剪、使用 CDN 托管大文件。
  5. 传输优化: 在服务器端开启 Gzip/Brotli 压缩。

34. uni-app 跨端兼容的常见问题?

  1. API 兼容性: 不同平台(H5/小程序/App)API 支持不一致。解决方案: 查阅文档,使用 条件编译 (// #ifdef H5) 编写平台特定代码。
  2. 样式兼容性: 单位、选择器和 Flex 布局的差异,尤其在 nvue 中。解决方案: 优先使用 Flex 布局,使用 rpx 作为尺寸单位。
  3. 原生组件层级: <video>, <map> 等原生组件层级最高。解决方案: 在这些组件上覆盖内容时,使用 cover-viewcover-image

35. Vue3 如何做骨架屏优化首屏体验?

骨架屏通过在数据加载前展示页面轮廓来优化用户感知体验。

  1. 手动编写: 创建一个与内容结构相似的 Skeleton 组件,并使用 CSS 动画实现加载效果。
  2. 组件控制: 在页面中使用 v-ifel-skeleton 等组件,通过一个 loading 状态来控制显示骨架屏还是真实内容。
  3. 自动化方案(高级): 使用 Puppeteer 等工具,在构建时自动截取页面结构,生成高保真的骨架屏组件代码,并内联到 HTML 中。

四、实战经验类

36. 如何在 Vue 项目中做前端埋点?

通常采用 混合埋点 方案:

  1. 代码埋点(核心):
    • 实现: 封装一个 tracker 模块,通过 navigator.sendBeaconImage 发送请求。
    • 使用: 通过 app.provideglobalProperties 注入到组件中。在关键业务操作(如购买、注册)处手动调用 this.$tracker.trackClick(...) 并附带业务参数。
    • PV 自动上报: 结合 Vue Router 的 afterEach 导航守卫自动上报页面浏览事件。
  2. 无痕埋点(基础): 通过全局监听 DOM 事件,自动采集用户点击和行为路径(通常由第三方或自研 SDK 实现)。

37. 如何设计 Vue 项目的权限系统?

权限系统分为 路由权限元素权限

  1. 权限数据获取: 登录后,从后端获取用户角色的 权限码列表(如 user:create)。
  2. 路由权限: 在 Vue Router 的 beforeEach 导航守卫 中实现。
    • 检查用户权限信息是否存在,如果不存在则异步获取。
    • 使用 router.addRoute(),根据用户的权限码过滤并动态注册可访问的路由表。
    • 使用 next({ ...to, replace: true }) 确保重定向。
  3. 元素权限: 通过 自定义指令 v-permission 实现。
    • 指令的 mounted 钩子读取指令值(所需权限码),检查用户是否拥有该权限。
    • 如果没有权限,则直接从 DOM 中移除元素 (el.parentNode.removeChild(el))。

38. 项目中主题色动态切换的实现方案?

基于 CSS 变量 (CSS Custom Properties) 的方案是最佳实践。

  1. 定义变量::root 下定义主色、背景色等 CSS 变量(如 --el-color-primary)。
  2. 使用变量: 在所有组件样式中使用 var(--variable-name) 引用颜色。
  3. 动态切换:
    • 预定义主题: 通过 JS 切换 <html> 元素的 class(如 light / dark),对应 class 下定义不同的 CSS 变量值。
    • 自定义颜色: 使用 JS 调用 document.documentElement.style.setProperty('--el-color-primary', newColor) 动态修改变量值。

39. Nuxt 如何实现服务端缓存?

Nuxt 3 的服务端引擎 Nitro 提供了强大的缓存能力。

  1. 路由规则缓存 (routeRules): 最推荐。nuxt.config.ts 中为特定路由配置 isr(增量静态生成)或 cache 策略,Nitro 会缓存整个页面或 API 响应。
  2. 服务端函数缓存 (cachedFunction): 在服务端 API 或工具函数中使用 cachedFunction 包裹耗时的计算或数据获取逻辑,实现函数级别的精细缓存。
  3. 外部缓存层: 集成 Redis 或 Varnish/Nginx 等反向代理层进行缓存,适用于高性能和分布式部署。

40. pc端项目部署更新后,如何通知用户去主动刷新?有什么方案

最佳方案:基于文件 Hash 的轮询检查。

  1. 生成版本文件: 每次部署时,生成一个不缓存的 version.json 文件,内含当前版本号(如 Git Hash)。
  2. 前端轮询: 客户端定时(如 5 分钟)请求该文件,并比较版本号。
  3. 提示刷新: 如果版本号不一致,说明有新版本部署,弹出通知(如 ElNotification),引导用户点击按钮执行 location.reload(true) 强制刷新。

41. Three.js 如何处理模型交互(如点击选中)?

使用 光线投射 (Raycasting)

  1. 标准化坐标: 将屏幕上的鼠标 clientX/Y 坐标转换为 Three.js 的标准化设备坐标 (NDC) [-1, 1]
  2. 创建 Raycaster: 使用 new THREE.Raycaster() 并调用 raycaster.setFromCamera(mouse, camera),从摄像机向鼠标方向发射一条射线。
  3. 相交检测: 调用 raycaster.intersectObjects(objects) 检测射线与场景中的哪些物体相交。
  4. 处理结果: 检查返回的相交数组,通常选取第一个相交物体(最近的),对其进行高亮或其他交互操作。

42. Vue 项目中如何避免内存泄漏?

核心是 在组件销毁时(onUnmounted)手动清理不受 Vue 自动管理的所有外部资源

  1. 清理事件监听器: 移除在 window, document 或其他全局对象上添加的所有 addEventListener 监听器。
  2. 清理定时器: 清除所有 setTimeoutsetInterval
  3. 销毁第三方库实例: 手动调用第三方库(如 ECharts, Three.js 渲染器)提供的 dispose()destroy() 方法来释放其占用的内存。
  4. 避免全局引用: 避免在 Vue 实例外部持有对组件内部响应式数据或 DOM 节点的持久引用。

43. 微前端项目如何统一 UI 风格?

  1. 设计系统: 建立一套统一的设计规范(颜色、字体、间距、组件行为)。
  2. 公共组件库: 将核心组件封装成一个独立的组件库。
  3. Module Federation (推荐): 利用模块联邦在运行时共享这个公共组件库,确保所有子应用使用同一份 UI 代码,解决了依赖重复和版本不一致的问题。
  4. CSS 变量: 全局加载一套基础 CSS 变量,确保所有子应用的主题色和基础样式一致。

44. Vue 项目如何实现国际化 i18n?

使用 vue-i18n 库。

  1. 配置: 创建 createI18n 实例,设置默认语言和回退语言,并传入各语言的翻译文件 (messages)。
  2. 模板使用: 在模板中使用 {{ $t('key') }} 或 Composition API 中的 t('key') 函数。
  3. 切换语言: 通过修改 i18n.global.locale 的响应式属性,视图会自动更新。
  4. 优化: 对于大型应用,将语言文件设置为 异步组件,按需懒加载,以减小首屏体积。

45. 前端如何与后端协作优化大数据渲染?

核心是前后端共同实现 数据分片、按需提供

  1. API 协议: 统一接口协议,支持分页(page/pageSize)或无限加载(offset/limit)。
  2. 后端分片: 后端在数据库层面进行高效分页查询,只返回前端请求的数据子集。
  3. 数据聚合/抽样: 对于可视化场景(如大型图表),后端应根据前端的缩放级别,返回聚合或抽样后的数据,避免传输大量原始数据。
  4. 动态加载: 树形结构或复杂列表应采用懒加载模式,前端按需请求子节点或下一批数据。
  5. 实时数据: 使用 WebSocket 进行流式传输增量数据,而不是频繁轮询。

46. 如果线上应用出现白屏问题,你会从哪些方面进行排查?

  1. 信息收集: 确定影响范围(所有用户/特定用户)、浏览器和最近的发布记录。
  2. 前端监控平台: 检查 Sentry 等平台是否有致命的 JS 错误堆栈,定位到引发白屏的代码行。
  3. 网络检查 (F12 Network): 检查关键 JS/CSS 资源文件是否加载失败(404/500),判断是否是 CDN 或部署问题。
  4. 控制台检查 (F12 Console): 查找应用初始化阶段是否有阻塞性的 JS 报错。
  5. 服务端/配置检查: 确认 API 接口是否正常,服务器配置是否正确,如 Gzip 压缩是否导致文件损坏。
  6. 代码回滚: 如果无法快速定位,立即回滚到上一个稳定版本。

47. 设计一个庞大陈旧的 Vue 2 项目向 Vue 3 迁移的策略。

采用渐进式、不中断业务的迁移策略:

  1. 环境共存: 引入 @vue/compat (迁移构建),让 Vue 3 兼容 Vue 2 的语法,使旧代码能在新环境下运行。
  2. 引入 TS/Vite: 将构建系统从 Vue CLI/Webpack 迁移到 Vite,并配置 TypeScript (allowJs: true)。
  3. 自下而上迁移组件: 从最底层的、依赖最少的叶子组件开始,将其重构为 Composition API + <script setup lang="ts"> 语法。
  4. 状态分步升级: 新模块使用 Pinia,旧 Vuex 模块逐步重构迁移到 Pinia。
  5. 清理与收尾: 当所有核心代码都迁移完成后,移除 @vue/compat,使项目完全运行在纯 Vue 3 模式下。

48. 如何实现一个知识图谱(圆形拖拽、连线、撤销)的设计方案?

  1. 技术选型: 优先选择 SVG。SVG 图形是 DOM 元素,天然支持事件监听和交互,相比 Canvas 更容易实现拖拽和点击选中。
  2. 渲染层:
    • 连线: 使用 SVG 的 <path> 元素绘制,路径坐标根据源节点和目标节点的实时位置动态计算。
    • 节点: 使用 SVG 的 <circle><text> 封装在 <g> 元素中,使用 transform: translate() 定位。
  3. 交互(拖拽): 监听节点的 mousedown 事件,在画布的 mousemove 事件中更新节点在 Pinia Store 中的 x/y 坐标,视图自动响应更新。
  4. 撤销/重做: 采用 命令模式 (Command Pattern)。将每个操作(移动节点、添加连线)封装成一个包含 execute()undo() 方法的命令对象,并维护 undoStackredoStack 两个堆栈。