1. 什么是 Vue.js?它的核心特點是什么?
Vue.js 是一個漸進式 JavaScript 框架,用于構建用戶界面。它的核心特點包括:
- 響應式數據綁定
- 組件化開發
- 虛擬 DOM
- 指令系統
- 輕量級且易于集成
- 豐富的生態系統(Vue Router, Vuex, Vue CLI等)
2. Vue 的雙向數據綁定原理是什么?
Vue 使用數據劫持結合發布者-訂閱者模式實現雙向綁定:
1.通過 Object.defineProperty() 或 Proxy 對數據對象進行劫持2. 在 getter 中收集依賴(Watcher)3. 在 setter 中通知變化,觸發更新4. 編譯器解析模板指令,初始化視圖5. Watcher 作為橋梁,連接 Observer 和 Compile
3. Vue 2.x 和 Vue 3.x 的主要區別有哪些?
1. 響應式系統:Vue 2 使用 Object.defineProperty,Vue 3 使用 Proxy
2. 性能:Vue 3 打包體積更小,虛擬 DOM 重寫,性能更好
3. Composition API:Vue 3 引入新的代碼組織方式
4. 片段支持:Vue 3 支持多根節點組件
5. Teleport 和 Suspense:Vue 3 新增的內置組件
6. TypeScript 支持:Vue 3 有更好的 TS 集成
7. 自定義渲染器 API
8. 全局 API 改為應用實例 API
4. 什么是 MVVM 模式?Vue 是如何實現 MVVM 的?
MVVM 是 Model-View-ViewModel 的縮寫:- Model:數據模型- View:UI 界面- ViewModel:連接 View 和 Model 的橋梁Vue 實現 MVVM:1. View:模板(template)2. Model:數據對象(data)3. ViewModel:Vue 實例,通過響應式系統和模板編譯連接 View 和 Model
5. Vue 的生命周期鉤子有哪些?分別在什么階段調用?
Vue 2.x 生命周期:beforeCreate:實例初始化后,數據觀測之前
created:實例創建完成,數據觀測完成
beforeMount:掛載開始之前
mounted:實例掛載到 DOM 后
beforeUpdate:數據更新時,DOM 更新前
updated:數據更新后,DOM 更新完成
beforeDestroy:實例銷毀前
destroyed:實例銷毀后
Vue 3.x 對應:
beforeCreate → 使用 setup()
created → 使用 setup()
beforeMount → onBeforeMount
mounted → onMounted
beforeUpdate → onBeforeUpdate
updated → onUpdated
beforeUnmount → onBeforeUnmount
unmounted → onUnmounted
6. Vue 組件間通信的方式有哪些?
1. 父子組件通信:Props 向下傳遞自定義事件向上傳遞 ($emit)v-model / .sync 語法糖parent/children (不推薦)ref 獲取組件實例2. 兄弟組件通信:通過共同的父組件中轉Event BusVuex3. 跨層級通信:provide / injectVuex全局事件總線4. 其他:attrs/listeners (Vue 2)v-bind="$attrs" (Vue 3)狀態管理庫 (Vuex, Pinia)
7. 什么是單向數據流?為什么 Vue 要采用這種設計?
單向數據流是指:
父組件通過 props 向子組件傳遞數據
子組件不能直接修改 props,只能通過事件通知父組件修改
原因:
使數據流更易于理解和調試
防止子組件意外修改父組件狀態
降低組件間耦合度
更好的維護性和可預測性
8. 動態組件是什么?如何使用?
動態組件是通過 <component>
元素和 is 特性實現的組件動態切換:
<component :is="currentComponent"></component>
使用場景:
標簽頁切換
根據條件渲染不同組件
動態布局系統
注意事項:
可以使用 <keep-alive> 緩存組件狀態
切換時組件會銷毀和重建
9. 異步組件是什么?如何實現?
異步組件是按需加載的組件,可以提高首屏加載速度。
Vue 2.x 實現:
components: {AsyncComponent: () => import('./AsyncComponent.vue')
}
Vue 3.x 新增 defineAsyncComponent:
import { defineAsyncComponent } from 'vue'const AsyncComp = defineAsyncComponent(() => import('./components/AsyncComponent.vue')
)
高級配置:
const AsyncComp = defineAsyncComponent({loader: () => import('./Foo.vue'),loadingComponent: LoadingComponent,errorComponent: ErrorComponent,delay: 200,timeout: 3000
})
10. 什么是函數式組件?有什么特點?
函數式組件是無狀態、無實例的組件,渲染開銷小。
特點:
沒有響應式數據
沒有實例(this)
只接受 props
無生命周期鉤子
渲染性能高
Vue 2.x 聲明:
Vue.component('functional-comp', {functional: true,render(h, context) {// ...}
})
Vue 3.x 聲明:
import { h } from 'vue'
const FunctionalComp = (props, context) => {return h('div', props.msg)
}
11. v-if 和 v-show 的區別是什么?
v-if:條件渲染,元素不存在于 DOM 中,切換時銷毀/重建組件
v-show:條件顯示,元素始終存在于 DOM 中,只是切換 display 屬性
使用場景:
v-if:切換頻率低,條件不太可能改變
v-show:頻繁切換,初始渲染成本高
性能考慮:
v-if 有更高的切換開銷
v-show 有更高的初始渲染開銷
12. v-for 指令的 key 屬性有什么作用?
key 的作用:
幫助 Vue 識別節點身份,高效更新虛擬 DOM
避免就地復用元素
維護組件狀態和子組件狀態
最佳實踐:
使用唯一標識作為 key
避免使用索引作為 key(當列表順序變化時會有問題)
在 v-for 中總是提供 key
13. v-model 的原理是什么?如何自定義 v-model?
??答案??:
v-model 是語法糖,默認相當于:
<input :value="value" @input="value = $event.target.value" />
自定義組件 v-model (Vue 2.x):
model: {prop: 'checked',event: 'change'
},
props: {checked: Boolean
}
Vue 3.x 支持多個 v-model:
<ChildComponent v-model:title="title" v-model:content="content" />
14. Vue 有哪些內置指令?各自的作用是什么?
??答案??:
常用內置指令:
v-text:更新元素的 textContent
v-html:更新元素的 innerHTML
v-show:條件顯示
v-if/v-else-if/v-else:條件渲染
v-for:列表渲染
v-on (@):綁定事件
v-bind (:):綁定屬性
v-model:雙向綁定
v-slot (#):插槽
v-pre:跳過編譯
v-once:只渲染一次
v-memo:記憶渲染 (Vue 3.2+)
v-cloak:防止閃現
15. 自定義指令是什么?如何實現?
??答案??:
自定義指令用于對普通 DOM 元素進行底層操作。
注冊全局指令:
// Vue 2
Vue.directive('focus', {inserted(el) {el.focus()}
})// Vue 3
app.directive('focus', {mounted(el) {el.focus()}
})
注冊局部指令:
directives: {focus: {mounted(el) {el.focus()}}
}
鉤子函數 (Vue 2 → Vue 3):
bind → beforeMount
inserted → mounted
update → 移除,改用 updated
componentUpdated → updated
unbind → unmounted
16. Vue 2.x 的響應式原理是什么?有什么缺陷?
??答案??:
原理:
使用 Object.defineProperty 劫持對象屬性
在 getter 中收集依賴
在 setter 中通知更新
每個組件實例對應一個 Watcher 實例
缺陷:
無法檢測對象屬性的添加或刪除(需要 Vue.set/Vue.delete)
無法檢測數組索引和長度的變化
對 ES6+ 的 Map、Set 等不支持
初始化時遞歸遍歷所有屬性,性能有影響
17. Vue 3.x 的響應式系統有什么改進?
??答案??:
改進:
使用 Proxy 代替 Object.defineProperty可以檢測屬性添加/刪除支持 Map、Set 等數據結構
性能優化:惰性響應式(按需響應)更好的緩存機制
更精確的變更檢測
支持嵌套對象的自動解包
獨立的響應式模塊(可單獨使用)
18. Vue.set/Vue.delete 的作用是什么?Vue 3 中還需要嗎?
??答案??:
Vue 2.x 中:
Vue.set:向響應式對象添加新屬性并觸發視圖更新
Vue.delete:刪除屬性并觸發視圖更新
Vue 3.x 中:
不再需要,因為 Proxy 可以檢測到屬性的添加和刪除
但仍保留了 set 和 delete 的 API 用于兼容
19. 什么是響應式數據的副作用函數?Vue 中如何收集依賴?
??答案??:
副作用函數是指會對外部產生影響的函數,如修改 DOM、發送請求等。
Vue 收集依賴的過程:
在組件渲染時,會執行 render 函數訪問響應式數據
觸發數據的 getter,將當前 Watcher(副作用函數)添加到依賴中
數據變化時,觸發 setter,通知所有依賴的 Watcher 更新
Watcher 執行更新函數,重新渲染或執行副作用
20. computed 和 watch 的區別是什么?
??答案??:
computed:
計算屬性,基于依賴緩存
必須有返回值
適合派生狀態
同步操作
watch:
觀察特定數據變化
無返回值
適合執行異步或復雜操作
可以觀察多個數據源
使用場景:
computed:模板中的復雜表達式、數據格式化
watch:數據變化時需要執行異步操作或復雜邏輯
虛擬 DOM 和渲染
21. 什么是虛擬 DOM?它的優點是什么?
??答案??:
虛擬 DOM 是真實 DOM 的輕量級 JavaScript 表示。
優點:
減少直接操作 DOM 的性能開銷
提供跨平臺能力(如 SSR、Native 渲染)
高效的差異比較算法(diff)
批量更新 DOM
開發體驗更接近聲明式編程
工作原理:
用 JavaScript 對象表示 DOM 結構
狀態變化時生成新的虛擬 DOM
比較新舊虛擬 DOM (diff)
將差異應用到真實 DOM (patch)
22. Vue 的 diff 算法是怎樣的?
??答案??:
Vue 的 diff 算法特點:
同級比較,不跨級
使用 key 識別節點身份
雙端比較策略(Vue 3 優化為更高效的算法)
優先處理特殊情況(如相同節點、文本節點)
優化策略:
靜態節點提升(Vue 3)
事件緩存
區塊樹優化(Vue 3)
更高效的 patch 標志
23. Vue 3 在虛擬 DOM 方面有哪些優化?
??答案??:
Vue 3 虛擬 DOM 優化:
靜態提升:將靜態節點提升到渲染函數外
補丁標志:為動態節點添加標志,減少比較范圍
緩存事件處理函數
區塊樹:將靜態和動態內容分離
更高效的 diff 算法
支持片段(多根節點)
更快的掛載和更新性能
24. 什么是渲染函數?什么情況下需要使用渲染函數?
??答案??:
渲染函數是用于編程式創建虛擬 DOM 的函數(h 函數)。
使用場景:
動態性很強的組件
需要更靈活的模板邏輯
高階組件
需要 JavaScript 的完整編程能力
性能敏感場景(比模板更高效)
示例:
render(h) {return h('div', { class: 'container' }, [h('h1', 'Title'),this.showSubtitle ? h('h2', 'Subtitle') : null])
}
25. Vue 3 的 h 函數有什么變化?
??答案??:
Vue 3 中 h 函數的變化:
需要從 vue 顯式導入
更靈活的參數:可以省略不用的參數props 結構更一致
支持 VNode 的標準化
更好的 TypeScript 支持
Vue 2:
h('div', { class: 'foo', on: { click: handler } }, 'hello')
Vue 3:
h('div', { class: 'foo', onClick: handler }, 'hello')
路由系統
26. Vue Router 的導航守衛有哪些?如何使用?
??答案??:
導航守衛分類:
全局守衛:beforeEach:前置守衛beforeResolve:解析守衛afterEach:后置鉤子路由獨享守衛:beforeEnter組件內守衛:beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave
使用示例:
router.beforeEach((to, from, next) => {// 必須調用 next()
})// 組件內
beforeRouteLeave(to, from, next) {// 確認離開?next(confirm('確認離開?'))
}
27. 路由懶加載的原理是什么?如何實現?
??答案??:
路由懶加載是通過動態導入實現的代碼分割技術。
原理:
使用動態 import() 語法
Webpack 將其識別為代碼分割點
路由被訪問時才加載對應 chunk
實現:
const routes = [{path: '/about',component: () => import('./views/About.vue')}
]
Vue 3 還可以使用 defineAsyncComponent:
const About = defineAsyncComponent(() => import('./About.vue'))
28. Vue Router 有幾種路由模式?區別是什么?
??答案??:
兩種主要模式:
hash 模式:使用 URL hash (#)兼容性好不需要服務器配置示例:http://example.com/#/about
history 模式:
使用 HTML5 History API
URL 更美觀
需要服務器配置(避免 404)
示例:http://example.com/about
配置:
const router = createRouter({history: createWebHashHistory(), // hashhistory: createWebHistory(), // history
})
29. 如何實現動態路由?有哪些應用場景?
??答案??:
實現方式:
使用冒號定義動態參數:
{ path: ‘/user/:id’, component: User }
通過 props 接收參數:
{ path: ‘/user/:id’, component: User, props: true }
編程式導航:
router.push('/user/' + userId)
應用場景:
用戶個人主頁
商品詳情頁
博客文章頁
任何需要根據 ID 展示不同內容的頁面
30. 如何實現路由鑒權?
??答案??:
常見鑒權方案:
路由元信息 + 全局守衛:
{path: '/admin',meta: { requiresAuth: true }
}router.beforeEach((to, from, next) => {if (to.matched.some(record => record.meta.requiresAuth)) {if (!auth.isLoggedIn()) {next('/login')} else {next()}} else {next()}
})
動態路由:
根據權限動態生成路由表
使用 router.addRoute() 添加路由
組合式 API (Vue 3):
import { onBeforeRouteUpdate } from 'vue-router'onBeforeRouteUpdate((to, from, next) => {// 鑒權邏輯
})
31. Vuex 的核心概念有哪些?
??答案??:
Vuex 核心概念:
State:單一狀態樹
Getters:計算屬性
Mutations:同步修改狀態(commit)
Actions:異步操作(dispatch)
Modules:模塊化
工作流程:
組件 dispatch Action
Action commit Mutation
Mutation 修改 State
State 變化觸發組件更新
32. Vuex 和 Pinia 的主要區別是什么?
??答案??:
Pinia 是 Vuex 的替代方案,主要區別:
API 設計:Vuex 有 mutations/actionsPinia 只有 actions(可同步/異步)
TypeScript 支持:Pinia 有更好的 TS 支持
模塊化:Vuex 需要 modulesPinia 自動模塊化
體積:Pinia 更輕量
Composition API:Pinia 專為 Vue 3 設計
開發體驗:Pinia 更簡潔直觀
33. 什么情況下應該使用 Vuex/Pinia?
??答案??:
使用場景:
多個組件共享狀態
多個組件需要修改同一狀態
需要維護復雜的狀態邏輯
需要狀態的時間旅行調試
需要服務端渲染的狀態保持
不適合場景:
簡單應用(可以用 provide/inject)
父子組件通信(用 props/emit)
簡單全局狀態(可以用 reactive)
34. 如何實現 Vuex 的模塊熱重載?
??答案??:
Vuex 模塊熱重載配置:
if (module.hot) {module.hot.accept(['./modules/moduleA'], () => {const newModuleA = require('./modules/moduleA').defaultstore.hotUpdate({modules: {moduleA: newModuleA}})})
}
Pinia 自動支持熱更新:
if (import.meta.hot) {import.meta.hot.accept(acceptHMRUpdate(useStore, import.meta.hot))
}
35. Vuex 的嚴格模式是什么?有什么作用?
??答案??:
嚴格模式會深度監測狀態變更是否來自 mutation。
啟用:
const store = new Vuex.Store({strict: true
})
作用:
確保所有狀態變更都經過 mutation
防止在 mutation 外修改狀態
開發時更好的調試體驗
注意:
不要在生產環境使用(性能影響)
可以用發布時去除:strict: process.env.NODE_ENV !== 'production'
組合式 API
36. 什么是組合式 API?解決了什么問題?
??答案??:
組合式 API 是 Vue 3 引入的新代碼組織方式,包括:
setup 函數
ref 和 reactive
生命周期鉤子函數
自定義組合函數
解決的問題:
選項式 API 在復雜組件中邏輯分散
更好的邏輯復用
更好的 TypeScript 支持
更靈活的邏輯組織
更小的函數粒度
37. setup 函數是什么?如何使用?
??答案??:
setup 是組合式 API 的入口函數:
在 beforeCreate 之前調用
沒有 this
接收 props 和 context 參數
返回對象暴露給模板
示例:
setup(props, context) {const count = ref(0)function increment() {count.value++}return {count,increment}
}
context 包含:
attrs
slots
emit
expose
38. ref 和 reactive 的區別是什么?
??答案??:
ref:
用于基本類型(也可以用于對象)
通過 .value 訪問
模板中自動解包
更適合獨立的基本值
reactive:
用于對象
直接訪問屬性
解構會失去響應性
更適合復雜對象
轉換:
reactive({ count: 1 }) 類似 ref(1).value
ref(obj) 類似 reactive(obj)
39. 什么是自定義 hook?如何實現?
??答案??:
自定義 hook 是使用組合式 API 封裝的邏輯復用函數。
實現:
// useCounter.js
import { ref } from 'vue'export function useCounter(initialValue = 0) {const count = ref(initialValue)function increment() {count.value++}return {count,increment}
}
// 使用
import { useCounter } from './useCounter'setup() {const { count, increment } = useCounter()return { count, increment }
}
特點:
以 use 前綴命名
可以組合其他 hook
返回響應式狀態和方法
40. watch 和 watchEffect 的區別是什么?
??答案??:
watch:
明確指定偵聽源
惰性執行(默認)
可以獲取舊值
更精確控制觸發時機
watchEffect:
自動收集依賴
立即執行
沒有舊值
適合副作用清理
示例:
// watch
watch(count, (newVal, oldVal) => {})// watchEffect
watchEffect(() => {console.log(count.value)
})
清理副作用:
watchEffect((onInvalidate) => {const timer = setInterval(() => {})onInvalidate(() => clearInterval(timer))
})
41. 什么是 Teleport?使用場景是什么?
??答案??:
Teleport 是 Vue 3 內置組件,可以將內容渲染到 DOM 樹的指定位置。
使用:
<teleport to="body"><div class="modal">...</div>
</teleport>
場景:
模態框
通知提示
加載條
任何需要突破父組件 DOM 層級限制的 UI
注意:
to 可以是 CSS 選擇器或 DOM 元素
內容仍保持組件上下文(如數據、指令)
42. 什么是 Suspense?如何使用?
??答案??:
Suspense 是 Vue 3 內置組件,用于處理異步組件加載狀態。
使用:
<Suspense><template #default><AsyncComponent /></template><template #fallback><div>Loading...</div></template>
</Suspense>
工作原理:
等待異步組件加載
顯示 fallback 內容
加載完成后顯示默認內容
注意:
實驗性功能,API 可能變化
可以配合 async setup 使用
43. 什么是渲染函數 JSX?如何在 Vue 中使用 JSX?
??答案??:
JSX 是 JavaScript 的語法擴展,可以在 JavaScript 中編寫類似 HTML 的結構。
Vue 中使用:
安裝插件:
npm install @vue/babel-plugin-jsx -D
配置 babel:
plugins: [“@vue/babel-plugin-jsx”]
使用:
render() {return <div class="container">{this.message}</div>
}
Vue 3 中:
import { defineComponent } from 'vue'const Component = defineComponent({setup() {return () => <div>JSX in Vue 3</div>}
})
44. Vue 3 的 Fragment 是什么?有什么好處?
??答案??:
Fragment 允許組件有多個根節點。
Vue 2 中:
組件必須有且只有一個根元素
Vue 3 中:
好處:
更靈活的模板結構
減少不必要的包裝 div
更符合語義化
與 React 保持一致
45. 什么是自定義渲染器?使用場景是什么?
??答案??:
自定義渲染器 API 允許自定義 Vue 的渲染邏輯。
使用場景:
非 DOM 渲染:小程序CanvasWebGL終端輸出
特殊 DOM 操作需求
創建特定領域的框架
示例:
import { createRenderer } from 'vue'const { render, createApp } = createRenderer({patchProp,insert,remove,createElement// ...其他平臺特定API
})
46. Vue 應用常見的性能優化手段有哪些?
??答案??:
常見優化:
代碼層面:合理使用 v-if 和 v-show為 v-for 設置 key避免同時使用 v-if 和 v-for使用 computed 緩存計算拆分復雜組件使用 keep-alive 緩存組件打包層面:路由懶加載按需引入組件庫代碼分割壓縮代碼Tree-shaking運行時:減少響應式數據量避免不必要的組件渲染防抖/節流虛擬滾動 (virtual scroller)其他:SSRCDN服務端緩存
47. 什么是 keep-alive?如何使用?
??答案??:
keep-alive 是 Vue 內置組件,用于緩存不活動的組件實例。
使用:
<keep-alive><component :is="currentComponent"></component>
</keep-alive>
屬性:
include:匹配的組件名會被緩存
exclude:匹配的組件名不會被緩存
max:最多緩存組件實例數
生命周期:
activated:組件激活時
deactivated:組件停用時
48. Vue 3 的 v-memo 是什么?如何使用?
??答案??:
v-memo 是 Vue 3.2+ 新增指令,用于緩存模板子樹。
使用:
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">{{ item.text }}
</div>
工作原理:
依賴項不變時跳過更新
必須與 v-for 一起使用
可以顯著提升性能
場景:
大型列表
復雜條件渲染
頻繁更新的 UI
49. 如何分析 Vue 應用的性能瓶頸?
??答案??:
分析方法:
Vue Devtools:性能時間線組件渲染時間事件追蹤Chrome DevTools:Performance 面板Memory 面板Coverage 面板特定工具:webpack-bundle-analyzerspeed-measure-webpack-pluginLighthouse代碼層面:檢查不必要的重新渲染檢查大型響應式對象檢查內存泄漏
50. 如何實現虛擬滾動?有什么好處?
??答案??:
虛擬滾動只渲染可見區域的列表項。
實現方式:
使用第三方庫:vue-virtual-scrollervue-virtual-scroll-grid手動實現:計算可見區域動態渲染可見項處理滾動事件
好處:
減少 DOM 數量
提高渲染性能
支持超大型列表
更流暢的滾動體驗
51. Vue 組件的單元測試應該測試哪些方面?
??答案??:
測試重點:
渲染輸出:是否正確渲染條件渲染邏輯列表渲染用戶交互:點擊等事件表單輸入自定義事件狀態變更:props 變化數據變化計算屬性生命周期:掛載/卸載更新異步行為:API 調用定時器
52. 常用的 Vue 測試工具和庫有哪些?
??答案??:
常用工具:
測試運行器:JestVitest測試工具:Vue Test Utils (官方)Testing Library輔助工具:@vue/test-utilsvue-jestjest-transform-stub其他:Cypress (E2E)Storybook (可視化測試)
53. 如何測試 Vue 組件中的異步邏輯?
??答案??:
測試異步邏輯方法:
使用 async/await:
test('async test', async () => {await wrapper.find('button').trigger('click')expect(wrapper.text()).toContain('Updated')
})
模擬定時器:
jest.useFakeTimers()
// 觸發定時器
jest.runAllTimers()
模擬 API 調用:
jest.mock('axios')
axios.get.mockResolvedValue({ data: {} })
flush-promises:
await flushPromises()
54. 什么是快照測試?在 Vue 中如何實現?
??答案??:
快照測試是比較組件渲染結果與保存的快照是否一致。
實現:
test('component snapshot', () => {const wrapper = mount(MyComponent)expect(wrapper.html()).toMatchSnapshot()
})
特點:
第一次測試生成快照文件
后續測試比較結果
快照需提交到版本控制
適合靜態組件
注意:
快照不是替代品,需結合其他測試
動態內容可能導致失敗
定期更新快照
55. 如何測試 Vuex store?
??答案??:
測試 Vuex store 方法:
單元測試 mutations:
test('increment mutation', () => {const state = { count: 0 }mutations.increment(state)expect(state.count).toBe(1)
})
測試 getters:
test('evenOrOdd getter', () => {const state = { count: 1 }expect(getters.evenOrOdd(state)).toBe('odd')
})
測試 actions:
test('increment action', async () => {const commit = jest.fn()await actions.increment({ commit })expect(commit).toHaveBeenCalledWith('increment')
})
集成測試:
const store = createStore(options)
store.dispatch('action')
expect(store.state).toEqual(...)
56. 什么是 SSR?Vue 中如何實現 SSR?
??答案??:
SSR (Server-Side Rendering) 是在服務器端生成 HTML 發送到客戶端。
Vue 實現方式:
使用 Nuxt.js 框架
手動配置:vue-server-rendererExpress/Koa 服務器Webpack 配置
優點:
更好的 SEO
更快的內容到達時間
對低端設備更友好
缺點:
開發復雜度高
服務器負載大
部分庫需要特殊處理
- SSR 和 CSR 的區別是什么?
??答案??:
SSR (Server-Side Rendering):
在服務器生成完整 HTML
客戶端"激活"交互
首屏加載快
SEO 友好
服務器壓力大
CSR (Client-Side Rendering):
服務器返回空 HTML 和 JS
客戶端渲染所有內容
首屏加載慢
SEO 不友好
服務器壓力小
混合方案:
預渲染
部分 SSR
漸進式激活
- Vue SSR 的性能優化手段有哪些?
??答案??:
SSR 優化手段:
代碼層面:避免單例狀態使用 bundleRenderer組件級別緩存減少序列化數據基礎設施:使用 microcache負載均衡CDN流式渲染其他:延遲加載非關鍵組件預取數據服務端壓縮
59. 什么是 hydration?SSR 中如何處理?
??答案??:
hydration 是客戶端 Vue 接管服務器渲染的靜態 HTML 并使其交互的過程。
處理要點:
客戶端和服務器輸出必須匹配避免 hydration 不匹配警告特殊處理客戶端特有代碼:if (process.client) {// 只在客戶端執行的代碼
}使用 <ClientOnly> 組件包裝客戶端特有內容注意生命周期鉤子調用時機
60. 如何處理 SSR 中的身份認證?
??答案??:
SSR 認證處理:
Cookie 認證:服務器自動發送 cookie適合傳統 sessionToken 認證:服務器通過 initialState 傳遞 token客戶端存儲 token雙重驗證:服務器檢查 session客戶端檢查 token
注意:
避免在服務器上使用 localStorage
處理異步用戶狀態
統一客戶端和服務端狀態
61. Vue CLI 和 Vite 的區別是什么?
??答案??:
Vue CLI:
基于 Webpack
功能全面
配置復雜
啟動和熱更新較慢
適合復雜項目
Vite:
基于原生 ES 模塊
開發服務器極快
配置簡單
生產打包使用 Rollup
適合現代瀏覽器項目
選擇:
新項目推薦 Vite
已有 Vue CLI 項目可逐步遷移
62. 如何優化 Vue 應用的打包體積?
??答案??:
優化手段:
代碼分割:路由懶加載組件異步加載按需引入:組件庫按需導入工具函數按需導入壓縮:JS/CSS 壓縮圖片壓縮Gzip/Brotli分析:webpack-bundle-analyzer移除重復依賴其他:使用現代模式 (Vue CLI)外部化大型庫
63. 如何實現 Vue 應用的預渲染?
??答案??:
預渲染是在構建時生成靜態 HTML 文件。
實現方式:
使用 prerender-spa-plugin:
new PrerenderSPAPlugin({staticDir: path.join(__dirname, 'dist'),routes: ['/', '/about'],
})
使用 Vue CLI 插件:
vue add prerender-spa
使用 Vite 插件:
import { vitePrerender } from 'vite-plugin-prerender'
適用場景:
營銷頁面
內容不常變化的頁面
改善 SEO
64. 如何部署 Vue 應用到不同的環境?
??答案??:
部署方案:
靜態部署:Nginx/ApacheCDNGitHub Pages服務端渲染:Node.js 服務器Docker 容器Serverless現代部署:VercelNetlifyCloudflare Pages
環境變量管理:
.env 文件
Vue CLI 模式
Vite 環境變量
65. 如何處理 Vue 應用的跨域問題?
??答案??:
跨域解決方案:
開發環境:配置 devServer.proxy (Vue CLI)devServer: {proxy: {'/api': {target: 'http://localhost:3000',changeOrigin: true}}
}生產環境:后端配置 CORSNginx 反向代理API 網關其他方案:JSONP (僅 GET)后端轉發瀏覽器插件臨時解決
進階概念
66. 什么是高階組件?如何實現?
??答案??:
高階組件 (HOC) 是接收組件并返回新組件的函數。
實現:
function withLoading(WrappedComponent) {return {data() {return { isLoading: true }},mounted() {setTimeout(() => {this.isLoading = false}, 1000)},render(h) {if (this.isLoading) {return h('div', 'Loading...')}return h(WrappedComponent, {props: this.$props})}}
}
使用:
const EnhancedComponent = withLoading(MyComponent)
Vue 3 替代方案:
組合式函數
渲染函數
插槽
67. 什么是遞歸組件?如何使用?
??答案??:
遞歸組件是調用自身的組件。
使用:
通過 name 選項遞歸:
<template><div><my-component v-if="condition" /></div>
</template><script>
export default {name: 'MyComponent'
}
</script>
通過組件引用遞歸:
import RecursiveComponent from './RecursiveComponent.vue'
export default {components: {RecursiveComponent}
}
注意:
必須有終止條件
可能影響性能
適合樹形結構數據
68. 什么是作用域插槽?使用場景是什么?
??答案??:
作用域插槽允許子組件向插槽傳遞數據。
使用:
<slot :item="item" :index="index"></slot>
<template v-slot:default="slotProps">{{ slotProps.item }} - {{ slotProps.index }}
</template>
簡寫 (Vue 2.6+):
<template #default="{ item, index }">{{ item }} - {{ index }}
</template>
場景:
數據列表組件
表格組件
任何需要靈活內容渲染的組件
69. Vue 3 的 createApp 和 new Vue() 有什么區別?
??答案??:
區別:
創建方式:Vue 2: new Vue({...})Vue 3: createApp({...})全局 API:Vue 2: 全局修改 Vue 原型Vue 3: 應用實例作用域配置:Vue 2: 全局配置Vue 3: 每個應用獨立配置掛載:Vue 2: $mount()Vue 3: mount()
示例:
// Vue 2
new Vue({ el: ‘#app’ })
// Vue 3
createApp(App).mount(‘#app’)
70. 什么是響應式丟失問題?如何解決?
??答案??:
響應式丟失是指解構或展開響應式對象時失去響應性。
常見場景:
解構 props:
const { foo } = this.props // 失去響應性
展開響應式對象:
return { ...reactiveObj } // 失去響應性
解決方案:
使用 toRefs:
const { foo } = toRefs(props)
保持引用:
return { reactiveObj }
使用 computed:
const foo = computed(() => props.foo)
71. Vue 應用常見的錯誤有哪些?如何捕獲?
??答案??:
常見錯誤:
渲染錯誤
事件處理錯誤
生命周期鉤子錯誤
異步操作錯誤
自定義指令錯誤
捕獲方式:
全局錯誤處理:
app.config.errorHandler = (err, vm, info) => {// 處理錯誤
}
生命周期鉤子:
errorCaptured(err, vm, info) {// 捕獲子孫組件錯誤
}
異步錯誤:
window.addEventListener('unhandledrejection', e => {})
第三方監控:SentryBugsnag### 72. 如何處理 Vue 路由中的 404 頁面???答案??:
處理方式:通配符路由:```javascript
{ path: '/:pathMatch(.*)*', component: NotFound }
導航守衛:
router.beforeEach((to, from, next) => {if (!to.matched.length) {next('/404')} else {next()}
})
服務器配置 (history 模式):
location / {try_files $uri $uri/ /index.html;
}
73. Vue 3 的 effectScope 是什么?如何使用?
??答案??:
effectScope 是 Vue 3.2+ 特性,用于組織和管理 effect。
使用:
import { effectScope, reactive, watch } from 'vue'const scope = effectScope()scope.run(() => {const state = reactive({ count: 0 })watch(() => state.count, console.log)state.count++
})scope.stop() // 停止所有 effect
場景:
組件 setup 中管理 effect
可組合的函數中
測試時清理 effect
74. 如何處理 Vue 中的內存泄漏?
??答案??:
內存泄漏常見原因:
全局變量
未清除的定時器/事件監聽
未卸載的第三方庫
閉包
未清理的 Vue 相關資源
解決方案:
組件卸載時清理:
onUnmounted(() => {clearInterval(timer)eventBus.off('event', handler)})
避免意外全局變量使用弱引用 (WeakMap/WeakSet)使用內存分析工具定位
75. Vue 3 的 Suspense 如何處理錯誤?
??答案??:
Suspense 錯誤處理:
使用 onErrorCaptured:
onErrorCaptured((err) => {error.value = errreturn false // 阻止錯誤繼續向上傳播
})
錯誤邊界組件:
<Suspense><template #default><AsyncComponent /></template><template #fallback><div v-if="error">{{ error.message }}</div><div v-else>Loading...</div></template>
</Suspense>
全局錯誤處理:
app.config.errorHandler = (err) => {// 處理 Suspense 錯誤
}
76. Vue 3 中如何更好地使用 TypeScript?
??答案??:
最佳實踐:
使用 defineComponent:
import { defineComponent } from 'vue'export default defineComponent({// 類型推斷
})
類型化 props:
props: {message: {type: String as PropType<string>,required: true}
}
類型化 ref:
const count = ref<number>(0)
類型化事件:
const emit = defineEmits<{(e: 'update', value: string): void
}>()
類型化 computed:
const double = computed<number>(() => count.value * 2)
77. 如何為 Vue 組件定義 TypeScript 類型?
??答案??:
定義組件類型:
import { DefineComponent } from 'vue'interface Props {title: stringcount?: number
}interface Emits {(e: 'update', value: string): void
}const MyComponent: DefineComponent<Props, {}, {}, {}, {}, {}, {}, Emits> = {props: {title: String,count: Number},emits: ['update'],setup(props, { emit }) {// 類型推斷可用}
}
Vue 3.3+ 更簡潔:
defineProps<{title: stringcount?: number
}>()defineEmits<{update: [value: string]
}>()
78. 如何為 Vuex/Pinia 添加 TypeScript 支持?
??答案??:
Vuex 類型支持:
interface State {count: number
}const store = createStore<State>({state: {count: 0},mutations: {increment(state) {state.count++ // 類型推斷}}
})
Pinia 類型支持:
export const useStore = defineStore('main', {state: (): State => ({count: 0}),actions: {increment() {this.count++ // 類型推斷}}
})
組件中使用:
const store = useStore()
store.count // 類型安全
79. 如何為自定義 hook 添加類型?
??答案??:
自定義 hook 類型:
import { ref, Ref } from 'vue'interface UseCounterOptions {initialValue?: numberstep?: number
}interface UseCounterReturn {count: Ref<number>increment: () => voiddecrement: () => void
}export function useCounter(options: UseCounterOptions = {}): UseCounterReturn {const count = ref(options.initialValue || 0)function increment() {count.value += options.step || 1}function decrement() {count.value -= options.step || 1}return {count,increment,decrement}
}
80. Vue 3 中如何類型化全局屬性和方法?
??答案??:
類型化全局屬性:
// main.ts
app.config.globalProperties.$filters = {formatDate(date: Date): string {return date.toLocaleDateString()}
}// 類型聲明
declare module '@vue/runtime-core' {interface ComponentCustomProperties {$filters: {formatDate: (date: Date) => string}}
}// 組件中使用
const { proxy } = getCurrentInstance()
proxy.$filters.formatDate(new Date())
81. 如何實現權限控制系統?
??答案??:
權限控制實現方案:
路由級別:
{path: '/admin',meta: { requiresAdmin: true }
}router.beforeEach((to) => {if (to.meta.requiresAdmin && !user.isAdmin) {return '/login'}
})
組件級別:
<template><admin-panel v-if="user.isAdmin" />
</template>
指令級別:
Vue.directive('permission', {inserted(el, binding) {if (!checkPermission(binding.value)) {el.parentNode.removeChild(el)}}
})
動態菜單:根據權限生成菜單后端返回可訪問路由
82. 如何實現多主題切換功能?
??答案??:
主題切換實現:
CSS 變量方案:
:root {--primary-color: #42b983;
}.theme-dark {--primary-color: #333;
}function toggleTheme() {document.body.classList.toggle('theme-dark')
}
類名切換:
<div :class="[themeClass]"></div>
動態樣式表:
function loadTheme(themeName) {const link = document.createElement('link')link.href = `/themes/${themeName}.css`link.rel = 'stylesheet'document.head.appendChild(link)
}
狀態管理:將主題信息存儲在 Vuex/Pinia持久化到 localStorage
83. 如何實現全局加載狀態?
??答案??:
全局加載狀態實現:
使用狀態管理:
// store
state: { isLoading: false },
mutations: {SET_LOADING(state, value) {state.isLoading = value}
}// 組件
<loading-spinner v-if="$store.state.isLoading" />使用 provide/inject:// 根組件
provide('isLoading', ref(false))// 子組件
const isLoading = inject('isLoading')使用事件總線:// 請求攔截器
axios.interceptors.request.use(config => {eventBus.emit('loading', true)return config
})
組合式函數:
export function useLoading() {const isLoading = ref(false)function withLoading(fn) {return async (...args) => {isLoading.value = truetry {await fn(...args)} finally {isLoading.value = false}}}return { isLoading, withLoading }
}
84. 如何實現表單驗證系統?
??答案??:
表單驗證方案:
使用 Vuelidate:
import { required, email } from '@vuelidate/validators'export default {setup() {return {v$: useVuelidate()}},data() {return { email: '' }},validations: {email: { required, email }}
}
使用 VeeValidate:
<Form @submit="onSubmit"><Field name="email" rules="required|email" /><ErrorMessage name="email" />
</Form>
自定義驗證:
function validate(form) {const errors = {}if (!form.name) errors.name = 'Required'return errors
}
異步驗證:
async function checkEmailUnique(email) {const res = await api.checkEmail(email)return res.available
}
85. 如何實現拖拽排序功能?
??答案??:
拖拽排序實現:
使用 SortableJS:
import Sortable from 'sortablejs'onMounted(() => {Sortable.create(el, {onEnd: (e) => {// 處理排序}})
})
使用 Vue Draggable:
<draggable v-model="list" @end="onDragEnd"><div v-for="item in list" :key="item.id">{{ item.name }}</div>
</draggable>
原生實現:
function handleDragStart(e) {e.dataTransfer.setData('text/plain', e.target.id)
}function handleDrop(e) {const id = e.dataTransfer.getData('text/plain')// 重新排序
}
移動端支持:
使用 touch 事件
使用 Hammer.js 等庫
86. 如何設計大型 Vue 應用的目錄結構?
??答案??:
推薦目錄結構:
src/
├── assets/ # 靜態資源
├── components/ # 公共組件
│ ├── ui/ # 基礎UI組件
│ └── … # 其他組件
├── composables/ # 組合式函數
├── stores/ # 狀態管理
├── router/ # 路由配置
├── views/ # 頁面組件
├── services/ # API服務
├── utils/ # 工具函數
├── styles/ # 全局樣式
├── types/ # 類型定義
├── App.vue # 根組件
└── main.ts # 入口文件
模塊化方案:
按功能模塊劃分:src/modules/
├── auth/
│ ├── components/
│ ├── store/
│ └── services/
└── user/├── components/├── store/└── services/按業務領域劃分混合方式
87. 如何實現微前端架構中的 Vue 應用?
??答案??:
Vue 微前端方案:
使用 qiankun:
// 主應用
registerMicroApps([{name: 'vue-app',entry: '//localhost:7101',container: '#subapp',activeRule: '/vue'}
])// 子應用
export async function mount(props) {render(props)
}
使用 Module Federation:
// webpack 配置
new ModuleFederationPlugin({name: 'host',remotes: {app1: 'app1@http://localhost:3001/remoteEntry.js'}
})
其他方案:single-spaiframe
關鍵點:
樣式隔離
狀態隔離
路由協調
公共依賴
88. 如何設計可復用的組件庫?
??答案??:
組件庫設計要點:
組件設計原則:單一職責可組合明確的接口良好的文檔技術實現:使用 Vue CLI/Vite 打包支持按需導入類型定義主題定制文檔:Storybook示例代碼API 文檔發布:npm 包版本管理changelog測試:單元測試可視化測試端到端測試
89. 如何實現 Vue 應用的國際化?
??答案??:
國際化方案:
使用 vue-i18n:
import { createI18n } from 'vue-i18n'const i18n = createI18n({locale: 'en',messages: {en: { welcome: 'Welcome' },zh: { welcome: '歡迎' }}
})app.use(i18n)
組件中使用:
<p>{{ $t('welcome') }}</p>
動態切換語言:
i18n.global.locale = 'zh'高級功能:懶加載語言包復數處理日期/數字格式化
90. 如何實現 Vue 和原生應用的混合開發?
??答案??:
混合開發方案:
WebView 嵌入:原生應用內嵌 WebViewVue 應用適配移動端原生橋接:
// Android
window.androidBridge.callNativeMethod()// iOS
window.webkit.messageHandlers.nativeHandler.postMessage()
使用 Capacitor:
import { Plugins } from '@capacitor/core'
const { Camera } = Pluginsasync takePhoto() {const image = await Camera.getPhoto()
}
其他方案:
Cordova
NativeScript-Vue
Weex
91. Vue 3 的編譯器優化有哪些?
??答案??:
Vue 3 編譯器優化:
靜態節點提升:將靜態節點提升到渲染函數外避免重復創建 VNode補丁標志:標記動態節點類型減少 diff 時需要比較的內容區塊樹:將動態節點按結構劃分區塊減少需要追蹤的動態節點數量緩存事件處理函數:避免不必要的重新渲染更快的 SSR 渲染
92. Vue 3 的靜態提升是什么原理?
??答案??:
靜態提升原理:
編譯時分析模板:識別完全靜態的節點識別只有 class/style 動態的節點提升靜態節點:const _hoisted_1 = createVNode("div", null, "static content")function render() {return _hoisted_1
}運行時直接復用:跳過這些節點的 diff/patch大幅提升更新性能
效果:
減少 VNode 創建開銷
減少內存占用
提高渲染性能
93. Vue 3 的區塊樹優化是什么?
??答案??:
區塊樹 (Block Tree) 優化:
將模板劃分為區塊:每個區塊包含動態節點靜態內容作為整體處理動態節點收集:編譯時收集動態節點引用形成扁平數組結構更新時:直接遍歷動態節點數組跳過靜態內容比較
優勢:
減少虛擬 DOM 樹遍歷
更精確的更新目標
提高 diff 效率
94. Vue 3 的按需編譯是什么?如何實現?
??答案??:
按需編譯原理:
基于 ES 模塊的 tree-shaking:只打包實際使用的代碼移除未使用的功能編譯器優化:根據模板實際使用的功能生成代碼例如不使用 v-model 就不編譯相關代碼組合式 API 設計:按需導入功能函數更好的 tree-shaking
實現方式:
使用 Vite/Rollup
配置優化選項:
// vite.config.js
export default {build: {rollupOptions: {treeshake: true}}
}
95. Vue 3 的 CSS 變量注入是什么?如何使用?
??答案??:
CSS 變量注入允許在 JS 中定義 CSS 變量并在樣式中使用。
使用:
<script setup>
import { ref } from 'vue'const color = ref('red')
</script><template><div class="text">Hello</div>
</template><style>
.text {color: v-bind(color);
}
</style>
編譯為:
.text {color: var(--xxxxxx);
}
原理:
編譯時將 v-bind 轉換為 CSS 變量
運行時動態更新變量值
優勢:
更好的 JS-CSS 集成
動態主題支持
類型安全
綜合問題
96. Vue 3 相比 React 有哪些優勢和劣勢?
??答案??:
Vue 3 優勢:
更簡單的學習曲線
更靈活的模板和 JSX 支持
更精細的響應式系統
更小的運行時體積
更好的性能優化
組合式 API 更靈活
React 優勢:
更大的生態系統
更豐富的第三方庫
更成熟的移動端方案
更靈活的渲染目標
更早引入的并發特性
選擇考慮:
偏好模板語法選 Vue
需要最大靈活性選 React
性能敏感場景 Vue 可能更優
大型團隊 React 可能更合適
97. Vue 3 和 Svelte 的主要區別是什么?
??答案??:
主要區別:
編譯策略:Svelte 編譯為高效命令式代碼Vue 保留運行時響應式:Svelte 使用編譯時響應式Vue 使用運行時響應式系統狀態管理:Svelte 使用簡單的 storeVue 提供 Vuex/Pinia生態系統:Vue 有更成熟的生態系統Svelte 更輕量學習曲線:Svelte 更簡單Vue 提供更多高級功能
98. Vue 3 未來的發展方向是什么?
??答案??:
Vue 未來方向:
更好的 TypeScript 支持
更強大的編譯時優化
更小的運行時體積
更好的開發工具體驗
更完善的 SSR 支持
更強大的組合式 API
可能的并發渲染支持
更友好的移動端方案
社區趨勢:
Vite 成為標配
Pinia 取代 Vuex
組合式 API 成為主流
更多基于編譯的優化
99. 如何成為 Vue 高級開發者?
??答案??:
進階路徑:
深入理解核心原理:響應式系統虛擬 DOM編譯器掌握高級特性:自定義渲染器編譯器宏源碼定制性能優化專家:渲染性能打包優化內存管理架構設計能力:大型應用架構微前端組件庫設計社區貢獻:參與開源編寫插件分享經驗
100. 如何設計一個 Vue 技術架構面試題?
??答案??:
好的 Vue 架構面試題應包含:
技術選型:Vue 2 vs Vue 3狀態管理方案構建工具選擇應用結構:目錄組織代碼拆分模塊劃分性能考慮:加載性能運行時性能內存使用擴展性:新功能添加團隊協作長期維護實際場景:給定業務需求特定約束條件權衡取舍