Vue 面试核心知识点总结
Vue 面试核心知识点总结
生命周期详解
Vue 实例从创建到销毁的完整生命周期过程:
- 
BeforeCreate - 数据观测和事件初始化尚未开始
- el和- data都未初始化
- 适合添加loading效果
 
- 
Created - 完成数据观测、属性和方法运算
- data已初始化,但- el仍未显示
- 可在此阶段发起异步请求
- 若无 el选项,生命周期会暂停直到调用vm.$mount(el)
 
- 
BeforeMount - 模板编译完成,但尚未挂载到DOM
- 相关 render函数首次被调用
- 完成了 el和data初始化
 
- 
Mounted - 实例已挂载到DOM
- 可访问DOM元素
- 适合执行DOM操作或初始化第三方库
 
- 
BeforeUpdate - 数据更新前调用
- 发生在虚拟DOM重新渲染和打补丁之前
- 可获取更新前的DOM状态
 
- 
Updated - 数据更改导致的虚拟DOM重新渲染完成
- 避免在此钩子中修改状态,可能导致无限更新循环
 
- 
BeforeDestroy - 实例销毁前调用
- 实例仍完全可用
- 适合清除定时器、取消订阅等清理工作
 
- 
Destroyed - 实例销毁后调用
- 所有事件监听器和子实例已被移除
- 解除了所有响应式依赖
 
常用指令
- v-model: 双向数据绑定
- v-bind: 动态绑定属性
- v-show/- v-if: 条件渲染
- v-for: 列表渲染
- v-on: 事件绑定
- v-once: 一次性渲染
- v-html: 原始HTML渲染
- v-slot: 插槽内容分发
V-model 实现原理
Vue 的双向绑定是通过以下方式实现的:
<input v-bind:value="something" v-on:input="something = $event.target.value">
核心机制:
- 接受一个 value属性
- 在有新值时触发 input事件
- 仅适用于 input,textarea,select元素
修饰符:
- .lazy: 将- input事件改为- change事件触发
- .trim: 自动过滤首尾空白字符
- .number: 将输入转为数字类型
MVVM 架构模式
Model-View-ViewModel 模式解析:
- Model: 数据模型层,包含业务逻辑和数据操作
- View: UI展示层,负责数据可视化
- ViewModel:
- 连接 Model 和 View 的桥梁
- 处理用户交互
- 监听数据变化并更新视图
 
优势:
- 双向数据绑定自动同步视图和模型
- 解决了传统MVC模式中厚重的Controller问题
- 更好的可测试性和代码组织
组件通信方式
- 
父子组件通信 - 父→子:通过 props传递数据
- 子→父:通过 $emit触发事件
 
- 父→子:通过 
- 
非父子组件通信 - Vuex: 集中式状态管理
- Event Bus: 事件总线模式
- Provide/Inject: 依赖注入
 
- 
高级通信 - Slot: 内容分发
- $attrs/$listeners: 跨级传递
- $parent/$children: 直接访问组件实例
 
路由模式对比
| 特性 | Hash模式 | History模式 | 
|---|---|---|
| URL显示 | 带#号 | 普通URL | 
| 实现原理 | window.location.hash | HTML5 History API | 
| 服务器配置 | 无需特殊配置 | 需要后端支持 | 
| SEO友好度 | 较差 | 较好 | 
| 兼容性 | 所有浏览器 | 需要HTML5支持 | 
Vuex 核心概念
graph TD
    A[View] -->|Dispatch| B(Actions)
    B -->|Commit| C[Mutations]
    C -->|Mutate| D[State]
    D -->|Render| A
- State: 单一状态树,存储应用级状态
- Getters: 计算属性,用于派生状态
- Mutations: 同步修改状态(唯一途径)
- Actions: 提交 mutations,可包含异步操作
- Modules: 模块化组织复杂状态
性能优化技巧
- Keep-alive: 缓存不活跃组件
- Key属性: 高效更新虚拟DOM
- 懒加载: 异步组件和路由
- 函数式组件: 无状态组件优化
- 生产模式: 移除警告和开发工具
组件传参方式详解
路由传参
- 动态路由匹配
// router.js
{
  path: '/user/:id',
  component: User
}
// 获取参数
this.$route.params.id
- Query传参
// 传递
this.$router.push({ path: '/user', query: { id: 123 } })
// 获取
this.$route.query.id
- Props解耦
// router.js
{ 
  path: '/user/:id',
  component: User,
  props: true 
}
// 组件中直接使用props接收
props: ['id']
组件间传参
- 父子组件
// 父组件
<child :msg="message" @update="handleUpdate"/>
// 子组件
props: ['msg']
this.$emit('update', newValue)
- 非父子组件
// Event Bus实现
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
// 组件A
EventBus.$emit('eventName', data)
// 组件B
EventBus.$on('eventName', data => {})
- Vuex状态管理
// 获取状态
this.$store.state.count
// 提交mutation
this.$store.commit('increment')
// 分发action
this.$store.dispatch('incrementAsync')
计算属性 vs 侦听器
computed(计算属性)
特点:
- 基于依赖缓存
- 只有依赖变化才会重新计算
- 必须有返回值
- 适合同步计算
computed: {
  fullName() {
    return this.firstName + ' ' + this.lastName
  },
  // 完整写法
  reversedMessage: {
    get() { /*...*/ },
    set(newValue) { /*...*/ }
  }
}
watch(侦听器)
特点:
- 无缓存性
- 可执行异步操作
- 适合数据变化时执行副作用
watch: {
  // 简单写法
  question(newVal, oldVal) {
    // 执行异步操作
  },
  // 完整写法
  someObject: {
    handler(newVal, oldVal) {},
    deep: true,  // 深度监听
    immediate: true  // 立即执行
  }
}
路由跳转方式对比
| 方式 | 特点 | 使用场景 | 
|---|---|---|
| router.push() | 添加新记录,可回退 | 常规导航 | 
| router.replace() | 替换当前记录,不可回退 | 登录后跳转等不需要回退的场景 | 
| router.go(n) | 在历史记录中前进或后退 | 实现前进后退功能 | 
| location.href | 刷新页面,丢失状态 | 需要完全刷新页面的场景 | 
高级特性
动态组件
<component :is="currentComponent"></component>
异步组件
components: {
  AsyncComponent: () => import('./AsyncComponent.vue')
}
自定义指令
Vue.directive('focus', {
  inserted: function (el) {
    el.focus()
  }
})
过滤器
filters: {
  capitalize: function (value) {
    if (!value) return ''
    return value.toString().charAt(0).toUpperCase() + value.slice(1)
  }
}
性能优化实践
- 组件懒加载
const User = () => import('./User.vue')
- 路由懒加载
{
  path: '/dashboard',
  component: () => import('./Dashboard.vue')
}
- 函数式组件
Vue.component('functional-button', {
  functional: true,
  render(h, context) {
    return h('button', context.data, context.children)
  }
})
- 合理使用v-if和v-show
- v-if:切换开销大,适合不频繁切换的场景
- v-show:初始渲染开销大,适合频繁切换的场景
常见问题解决方案
跨域问题
- 开发环境:配置webpack devServer代理
- 生产环境:Nginx反向代理或后端设置CORS
样式隔离
- Scoped CSS
<style scoped>
/* 样式只作用于当前组件 */
</style>
- CSS Modules
<style module>
/* 生成唯一类名 */
</style>
错误处理
- 全局错误捕获
Vue.config.errorHandler = function (err, vm, info) {
  // 处理错误
}
- 异步错误捕获
async created() {
  try {
    await this.fetchData()
  } catch (error) {
    // 处理错误
  }
}
最佳实践建议
- 组件命名:使用PascalCase(如MyComponent)
- Prop定义:尽量详细指定类型和默认值
props: {
  msg: {
    type: String,
    required: true,
    validator: value => value.length > 0
  }
}
- 
状态管理原则: - 组件私有状态放在data中
- 组件间共享状态提升到父组件
- 全局共享状态使用Vuex
 
- 
代码组织: - 单一职责组件
- 按功能组织文件结构
- 合理拆分大型组件