🚀Vue面试必刷!从入门到精通,一文搞定Vue2/Vue3核心知识点

133 阅读5分钟

本文将从基础概念到高级特性,全面解析Vue2和Vue3的核心知识点,助你在面试中脱颖而出!

📋 目录

🎯 Vue基础概念

什么是Vue?

Vue是一个渐进式JavaScript框架,用于构建用户界面。它的核心特性包括:

  • 响应式数据绑定:数据变化自动更新视图
  • 组件化开发:可复用的组件系统
  • 虚拟DOM:高效的DOM更新机制
  • 单文件组件:.vue文件整合模板、逻辑、样式

Vue的核心设计理念

  1. 渐进式框架:可以逐步采用,从简单的视图层到复杂的SPA应用
  2. 声明式渲染:通过模板语法声明式地描述UI状态
  3. 组件化:将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的最新版本,带来了许多重要的改进和新特性:

  1. 性能提升:基于Proxy的响应式系统,更小的包体积
  2. 开发体验:组合式API提供更好的逻辑复用和代码组织
  3. 新特性:Teleport、Fragments、Suspense等
  4. TypeScript支持:更好的类型推导和开发体验

在面试中,除了掌握这些知识点,还要能够:

  • 解释原理和设计思路
  • 对比不同方案的优缺点
  • 结合实际项目经验
  • 展示代码实现能力

希望这篇文章能够帮助你在Vue面试中取得好成绩!🚀


关注我,获取更多前端技术干货! 📖

#Vue #前端面试 #Vue3 #JavaScript #前端开发