Vue 面试核心知识点总结

生命周期详解

Vue 实例从创建到销毁的完整生命周期过程:

  1. BeforeCreate

    • 数据观测和事件初始化尚未开始
    • eldata 都未初始化
    • 适合添加loading效果
  2. Created

    • 完成数据观测、属性和方法运算
    • data 已初始化,但 el 仍未显示
    • 可在此阶段发起异步请求
    • 若无 el 选项,生命周期会暂停直到调用 vm.$mount(el)
  3. BeforeMount

    • 模板编译完成,但尚未挂载到DOM
    • 相关 render 函数首次被调用
    • 完成了 eldata 初始化
  4. Mounted

    • 实例已挂载到DOM
    • 可访问DOM元素
    • 适合执行DOM操作或初始化第三方库
  5. BeforeUpdate

    • 数据更新前调用
    • 发生在虚拟DOM重新渲染和打补丁之前
    • 可获取更新前的DOM状态
  6. Updated

    • 数据更改导致的虚拟DOM重新渲染完成
    • 避免在此钩子中修改状态,可能导致无限更新循环
  7. BeforeDestroy

    • 实例销毁前调用
    • 实例仍完全可用
    • 适合清除定时器、取消订阅等清理工作
  8. 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">

核心机制:

  1. 接受一个 value 属性
  2. 在有新值时触发 input 事件
  3. 仅适用于 input, textarea, select 元素

修饰符:

  • .lazy: 将 input 事件改为 change 事件触发
  • .trim: 自动过滤首尾空白字符
  • .number: 将输入转为数字类型

MVVM 架构模式

Model-View-ViewModel 模式解析:

  • Model: 数据模型层,包含业务逻辑和数据操作
  • View: UI展示层,负责数据可视化
  • ViewModel:
    • 连接 Model 和 View 的桥梁
    • 处理用户交互
    • 监听数据变化并更新视图

优势:

  • 双向数据绑定自动同步视图和模型
  • 解决了传统MVC模式中厚重的Controller问题
  • 更好的可测试性和代码组织

组件通信方式

  1. 父子组件通信

    • 父→子:通过 props 传递数据
    • 子→父:通过 $emit 触发事件
  2. 非父子组件通信

    • Vuex: 集中式状态管理
    • Event Bus: 事件总线模式
    • Provide/Inject: 依赖注入
  3. 高级通信

    • 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
  1. State: 单一状态树,存储应用级状态
  2. Getters: 计算属性,用于派生状态
  3. Mutations: 同步修改状态(唯一途径)
  4. Actions: 提交 mutations,可包含异步操作
  5. Modules: 模块化组织复杂状态

性能优化技巧

  1. Keep-alive: 缓存不活跃组件
  2. Key属性: 高效更新虚拟DOM
  3. 懒加载: 异步组件和路由
  4. 函数式组件: 无状态组件优化
  5. 生产模式: 移除警告和开发工具

组件传参方式详解

路由传参

  1. 动态路由匹配
// router.js
{
  path: '/user/:id',
  component: User
}
// 获取参数
this.$route.params.id
  1. Query传参
// 传递
this.$router.push({ path: '/user', query: { id: 123 } })
// 获取
this.$route.query.id
  1. Props解耦
// router.js
{ 
  path: '/user/:id',
  component: User,
  props: true 
}
// 组件中直接使用props接收
props: ['id']

组件间传参

  1. 父子组件
// 父组件
<child :msg="message" @update="handleUpdate"/>

// 子组件
props: ['msg']
this.$emit('update', newValue)
  1. 非父子组件
// Event Bus实现
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

// 组件A
EventBus.$emit('eventName', data)

// 组件B
EventBus.$on('eventName', data => {})
  1. 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)
  }
}

性能优化实践

  1. 组件懒加载
const User = () => import('./User.vue')
  1. 路由懒加载
{
  path: '/dashboard',
  component: () => import('./Dashboard.vue')
}
  1. 函数式组件
Vue.component('functional-button', {
  functional: true,
  render(h, context) {
    return h('button', context.data, context.children)
  }
})
  1. 合理使用v-if和v-show
  • v-if:切换开销大,适合不频繁切换的场景
  • v-show:初始渲染开销大,适合频繁切换的场景

常见问题解决方案

跨域问题

  1. 开发环境:配置webpack devServer代理
  2. 生产环境:Nginx反向代理或后端设置CORS

样式隔离

  1. Scoped CSS
<style scoped>
/* 样式只作用于当前组件 */
</style>
  1. CSS Modules
<style module>
/* 生成唯一类名 */
</style>

错误处理

  1. 全局错误捕获
Vue.config.errorHandler = function (err, vm, info) {
  // 处理错误
}
  1. 异步错误捕获
async created() {
  try {
    await this.fetchData()
  } catch (error) {
    // 处理错误
  }
}

最佳实践建议

  1. 组件命名:使用PascalCase(如MyComponent
  2. Prop定义:尽量详细指定类型和默认值
props: {
  msg: {
    type: String,
    required: true,
    validator: value => value.length > 0
  }
}
  1. 状态管理原则:

    • 组件私有状态放在data中
    • 组件间共享状态提升到父组件
    • 全局共享状态使用Vuex
  2. 代码组织:

    • 单一职责组件
    • 按功能组织文件结构
    • 合理拆分大型组件

标签: 前端开发, Web开发技巧, Vuex, VueRouter

添加新评论