本文将从基础概念到高级特性,全面解析Vue2和Vue3的核心知识点,助你在面试中脱颖而出!
📋 目录
🎯 Vue基础概念
什么是Vue?
Vue是一个渐进式JavaScript框架,用于构建用户界面。它的核心特性包括:
- 响应式数据绑定:数据变化自动更新视图
- 组件化开发:可复用的组件系统
- 虚拟DOM:高效的DOM更新机制
- 单文件组件:.vue文件整合模板、逻辑、样式
Vue的核心设计理念
- 渐进式框架:可以逐步采用,从简单的视图层到复杂的SPA应用
- 声明式渲染:通过模板语法声明式地描述UI状态
- 组件化:将UI拆分为独立可复用的组件
🔄 Vue2 vs Vue3 核心差异
1. 性能提升
// Vue2 - 基于Object.defineProperty
const data = { message: 'Hello' }
Object.defineProperty(data, 'message', {
get() { return this._message },
set(value) {
this._message = value
// 触发更新
}
})
// Vue3 - 基于Proxy
const data = { message: 'Hello' }
const proxy = new Proxy(data, {
get(target, key) { return target[key] },
set(target, key, value) {
target[key] = value
// 触发更新
return true
}
})
2. 组合式API vs 选项式API
<!-- Vue2 - 选项式API -->
<template>
<div>
<p>{{ message }}</p>
<button @click="increment">点击次数: {{ count }}</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue2',
count: 0
}
},
methods: {
increment() {
this.count++
}
},
mounted() {
console.log('组件已挂载')
}
}
</script>
<!-- Vue3 - 组合式API -->
<template>
<div>
<p>{{ message }}</p>
<button @click="increment">点击次数: {{ count }}</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const message = ref('Hello Vue3')
const count = ref(0)
const increment = () => {
count.value++
}
onMounted(() => {
console.log('组件已挂载')
})
</script>
🚀 Vue3新特性深度解析
1. Composition API
Composition API是Vue3最重要的新特性,解决了Vue2中逻辑复用和代码组织的问题。
核心概念
// 响应式引用
import { ref, reactive, computed, watch } from 'vue'
// ref - 用于基本类型
const count = ref(0)
console.log(count.value) // 访问值
// reactive - 用于对象
const state = reactive({
name: '张三',
age: 25
})
console.log(state.name) // 直接访问
// computed - 计算属性
const doubleCount = computed(() => count.value * 2)
// watch - 监听器
watch(count, (newVal, oldVal) => {
console.log(`count从${oldVal}变为${newVal}`)
})
逻辑复用示例
// useCounter.js - 可复用的计数器逻辑
import { ref } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => count.value++
const decrement = () => count.value--
const reset = () => count.value = initialValue
return {
count,
increment,
decrement,
reset
}
}
// 在组件中使用
<script setup>
import { useCounter } from './useCounter'
const { count, increment, decrement, reset } = useCounter(10)
</script>
2. Teleport组件
Teleport允许将组件渲染到DOM树的其他位置,常用于模态框、通知等。
<template>
<div>
<button @click="showModal = true">打开模态框</button>
<Teleport to="body">
<div v-if="showModal" class="modal">
<div class="modal-content">
<h3>模态框内容</h3>
<button @click="showModal = false">关闭</button>
</div>
</div>
</Teleport>
</div>
</template>
<script setup>
import { ref } from 'vue'
const showModal = ref(false)
</script>
3. Fragments(片段)
Vue3支持多根节点,不再需要单一的根元素。
<!-- Vue2 - 必须有一个根元素 -->
<template>
<div>
<header>标题</header>
<main>内容</main>
<footer>底部</footer>
</div>
</template>
<!-- Vue3 - 支持多根节点 -->
<template>
<header>标题</header>
<main>内容</main>
<footer>底部</footer>
</template>
4. Suspense组件
Suspense用于处理异步组件和异步数据获取。
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
<script setup>
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
)
</script>
🔍 响应式原理详解
Vue2响应式原理
Vue2使用Object.defineProperty实现响应式,存在以下限制:
- 无法监听数组索引和length变化
- 无法监听对象属性的添加和删除
- 需要递归遍历对象
// Vue2响应式实现原理
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`获取${key}: ${val}`)
return val
},
set(newVal) {
if (val === newVal) return
console.log(`设置${key}: ${newVal}`)
val = newVal
// 触发更新
}
})
}
const data = { message: 'Hello' }
defineReactive(data, 'message', 'Hello')
Vue3响应式原理
Vue3使用Proxy实现响应式,解决了Vue2的所有限制:
// Vue3响应式实现原理
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
console.log(`获取${key}: ${target[key]}`)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
if (target[key] === value) return true
console.log(`设置${key}: ${value}`)
const result = Reflect.set(target, key, value, receiver)
// 触发更新
return result
},
deleteProperty(target, key) {
console.log(`删除${key}`)
return Reflect.deleteProperty(target, key)
}
})
}
const data = reactive({ message: 'Hello' })
响应式API对比
// Vue2
const vm = new Vue({
data: {
message: 'Hello'
}
})
// Vue3
import { reactive, ref } from 'vue'
// 对象响应式
const state = reactive({ message: 'Hello' })
// 基本类型响应式
const message = ref('Hello')
⏰ 生命周期对比
Vue2生命周期
export default {
beforeCreate() {
// 实例初始化之后,数据观测和事件配置之前
},
created() {
// 实例创建完成,数据观测、属性和方法配置完成
},
beforeMount() {
// 挂载开始之前,render函数首次被调用
},
mounted() {
// 实例挂载完成,DOM已创建
},
beforeUpdate() {
// 数据更新时调用,发生在虚拟DOM重新渲染之前
},
updated() {
// 数据更新导致的虚拟DOM重新渲染完成后调用
},
beforeDestroy() {
// 实例销毁之前调用
},
destroyed() {
// 实例销毁后调用
}
}
Vue3生命周期
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
export default {
setup() {
onBeforeMount(() => {
console.log('挂载前')
})
onMounted(() => {
console.log('挂载后')
})
onBeforeUpdate(() => {
console.log('更新前')
})
onUpdated(() => {
console.log('更新后')
})
onBeforeUnmount(() => {
console.log('卸载前')
})
onUnmounted(() => {
console.log('卸载后')
})
}
}
📡 组件通信方案
1. Props/Emit(父子通信)
<!-- 父组件 -->
<template>
<ChildComponent
:message="parentMessage"
@update="handleUpdate"
/>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const parentMessage = ref('来自父组件的数据')
const handleUpdate = (value) => {
console.log('子组件传递的数据:', value)
}
</script>
<!-- 子组件 -->
<template>
<div>
<p>{{ message }}</p>
<button @click="sendToParent">发送数据给父组件</button>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps({
message: String
})
const emit = defineEmits(['update'])
const sendToParent = () => {
emit('update', '来自子组件的数据')
}
</script>
2. Provide/Inject(跨层级通信)
<!-- 祖先组件 -->
<template>
<div>
<ChildComponent />
</div>
</template>
<script setup>
import { provide, ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const theme = ref('dark')
provide('theme', theme)
</script>
<!-- 后代组件 -->
<template>
<div :class="theme">
当前主题: {{ theme }}
</div>
</template>
<script setup>
import { inject } from 'vue'
const theme = inject('theme', 'light') // 默认值为'light'
</script>
3. Vuex/Pinia(状态管理)
// store.js - Pinia示例
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
},
decrement() {
this.count--
}
}
})
<!-- 组件中使用 -->
<template>
<div>
<p>计数: {{ counter.count }}</p>
<p>双倍: {{ counter.doubleCount }}</p>
<button @click="counter.increment">+</button>
<button @click="counter.decrement">-</button>
</div>
</template>
<script setup>
import { useCounterStore } from './store'
const counter = useCounterStore()
</script>
⚡ 性能优化策略
1. 虚拟列表
<template>
<div class="virtual-list" :style="{ height: totalHeight + 'px' }">
<div class="virtual-list-phantom" :style="{ height: totalHeight + 'px' }"></div>
<div class="virtual-list-content" :style="{ transform: `translateY(${offsetY}px)` }">
<div
v-for="item in visibleData"
:key="item.id"
class="virtual-list-item"
:style="{ height: itemHeight + 'px' }"
>
{{ item.content }}
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
const listData = ref([])
const scrollTop = ref(0)
const itemHeight = 50
const visibleCount = 10
// 生成大量数据
onMounted(() => {
listData.value = Array.from({ length: 10000 }, (_, index) => ({
id: index,
content: `项目 ${index}`
}))
})
const totalHeight = computed(() => listData.value.length * itemHeight)
const startIndex = computed(() => Math.floor(scrollTop.value / itemHeight))
const endIndex = computed(() => startIndex.value + visibleCount)
const offsetY = computed(() => startIndex.value * itemHeight)
const visibleData = computed(() =>
listData.value.slice(startIndex.value, endIndex.value)
)
const handleScroll = (e) => {
scrollTop.value = e.target.scrollTop
}
</script>
2. 懒加载
<template>
<div>
<img
v-for="image in images"
:key="image.id"
:src="image.src"
v-lazy="image.src"
alt="懒加载图片"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const images = ref([
{ id: 1, src: 'image1.jpg' },
{ id: 2, src: 'image2.jpg' },
// ... 更多图片
])
</script>
3. 组件懒加载
// 路由懒加载
const routes = [
{
path: '/home',
component: () => import('./views/Home.vue')
},
{
path: '/about',
component: () => import('./views/About.vue')
}
]
// 组件懒加载
const AsyncComponent = defineAsyncComponent(() =>
import('./components/HeavyComponent.vue')
)
🎯 面试高频考点
1. Vue2和Vue3的区别
答案要点:
- 性能提升:Proxy替代Object.defineProperty
- 组合式API:更好的逻辑复用和代码组织
- 新特性:Teleport、Fragments、Suspense
- 更好的TypeScript支持
- 更小的包体积
2. 响应式原理
答案要点:
- Vue2:Object.defineProperty,无法监听数组和对象属性变化
- Vue3:Proxy,可以监听所有变化,包括数组索引和对象属性
- 依赖收集和派发更新机制
3. 虚拟DOM原理
答案要点:
- 虚拟DOM是真实DOM的JavaScript对象表示
- 通过diff算法比较虚拟DOM差异
- 批量更新真实DOM,提高性能
- Vue3优化了diff算法,静态提升等
4. 组件通信方式
答案要点:
- Props/Emit:父子组件通信
- Provide/Inject:跨层级通信
- EventBus:事件总线(Vue3中已移除)
- Vuex/Pinia:状态管理
- $refs:直接访问子组件
5. 生命周期
答案要点:
- Vue2:beforeCreate、created、beforeMount、mounted等
- Vue3:onBeforeMount、onMounted等组合式API
- 理解每个阶段的用途和时机
6. 性能优化
答案要点:
- 虚拟列表
- 懒加载
- keep-alive缓存
- 合理使用v-show和v-if
- 避免不必要的响应式数据
💻 实战代码示例
1. 自定义Hook示例
// useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, defaultValue) {
const storedValue = localStorage.getItem(key)
const value = ref(storedValue ? JSON.parse(storedValue) : defaultValue)
watch(value, (newValue) => {
localStorage.setItem(key, JSON.stringify(newValue))
})
return value
}
// 使用示例
<script setup>
import { useLocalStorage } from './useLocalStorage'
const theme = useLocalStorage('theme', 'light')
const user = useLocalStorage('user', { name: '', age: 0 })
</script>
2. 自定义指令示例
// v-focus.js
export const focus = {
mounted(el) {
el.focus()
}
}
// v-permission.js
export const permission = {
mounted(el, binding) {
const { value } = binding
const hasPermission = checkPermission(value)
if (!hasPermission) {
el.parentNode?.removeChild(el)
}
}
}
// 使用示例
<template>
<input v-focus />
<button v-permission="'admin'">管理员按钮</button>
</template>
3. 插件开发示例
// myPlugin.js
export default {
install(app, options) {
// 全局属性
app.config.globalProperties.$formatDate = (date) => {
return new Date(date).toLocaleDateString()
}
// 全局组件
app.component('MyButton', {
template: '<button class="my-btn"><slot /></button>'
})
// 全局指令
app.directive('highlight', {
mounted(el, binding) {
el.style.backgroundColor = binding.value || 'yellow'
}
})
}
}
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import myPlugin from './myPlugin'
const app = createApp(App)
app.use(myPlugin)
app.mount('#app')
📚 总结
Vue3作为Vue的最新版本,带来了许多重要的改进和新特性:
- 性能提升:基于Proxy的响应式系统,更小的包体积
- 开发体验:组合式API提供更好的逻辑复用和代码组织
- 新特性:Teleport、Fragments、Suspense等
- TypeScript支持:更好的类型推导和开发体验
在面试中,除了掌握这些知识点,还要能够:
- 解释原理和设计思路
- 对比不同方案的优缺点
- 结合实际项目经验
- 展示代码实现能力
希望这篇文章能够帮助你在Vue面试中取得好成绩!🚀
关注我,获取更多前端技术干货! 📖
#Vue #前端面试 #Vue3 #JavaScript #前端开发