Vue 重点知识复习(一)

0 阅读8分钟

对 Vue 的理解

💡 核心定位:Vue 是一个渐进式的 JavaScript 框架,专注于构建用户界面。

核心思想

  • 数据驱动:通过数据变化自动更新视图
  • 组件化:将页面拆分成独立组件,提高代码复用性和可维护性

主要优势

  • 简单易用:模板语法易于理解和学习,可以快速构建交互式的 Web 应用程序
  • 灵活性高:支持多种开发模式和项目规模
  • 性能优越:高效的虚拟 DOM 和渲染机制
  • 扩展性强:丰富的官方插件(Vuex/Pinia、Vue Router 等)

核心特征

响应式数据绑定是 Vue 最核心的特性之一:

  • 通过对数据进行劫持和监听实现双向绑定
  • 数据变化自动更新视图,视图变化反映到数据
  • 清晰可预测的数据流,减少开发工作量

总之,Vue 平衡了灵活性与规范性,组件化设计促进了代码复用,响应式系统简化了状态管理,渐进式架构适应了不同工程需求,活跃的生态覆盖完整开发链路,是一个值得深入学习和使用的框架。

Vue 和 React 的区别

📊 核心区别对比

对比维度VueReact
模板语法基于 HTML 的模板语法,直接渲染 DOM采用 JSX 语法直接描述 UI 组件的结构和样式,通过渲染函数转化为真实 DOM
状态管理提供 VueX/Pinia 状态管理库,简单易维护提供 React Context 和 Redux 等工具,灵活可控
组件通信使用 props 和事件进行父子通信,支持 Vuex 跨组件通信通过 props 和回调函数通信,支持 Redux 跨组件通信
生命周期8 个钩子函数,细致易懂10 个钩子函数,包含过时和新引入的钩子
响应式原理双向数据绑定,自动更新页面单向数据流,数据从父组件传递到子组件
性能优化模板编译 + 虚拟 DOM,提供异步组件和 keep-alive虚拟 DOM + diff 算法,提供 React.PureComponent 和 React.memo

Vue2 和 Vue3 的区别

✨ Vue3 的核心改进

Vue3 作为 Vue 的最新版本,在性能可维护性特性方面都有显著提升:

改进维度具体说明
性能提升内部实现大量优化,渲染速度更快,内存占用更少
Composition API引入组合式 API,更好地组织和复用逻辑代码,提高可维护性
TypeScript 支持对 TypeScript 支持更加友好,提供完整的类型定义
Tree Shaking 支持更好的 Tree Shaking 支持,精确按需引入模块
更小体积核心库依赖更少,打包体积更小
新特性支持片段(Fragments)、Teleport、Suspense 等新特性

⚠️ 注意事项

Vue3 与 Vue2 之间不完全兼容,由于 API 发生了较大变化,需要进行相应的迁移工作。

Vue 的 data 里面如果有数组,如何检测数组的变化?

📌 数组变化检测的 4 种方法

1. 使用 watch 深度监听

适用场景:需要监听数组内部任意变化(包括元素属性变化)

watch: {
  myArray: {
    handler(newVal, oldVal) {
      console.log('数组变化了', newVal);
    },
    deep: true  // 关键:深度监听
  }
}

2. 使用 computed 间接监听

适用场景:只需要监听数组特定属性(如长度、某个元素值)的变化

computed: {
  arrayLength() {
    return this.myArray.length;
  }
}
// 当数组长度变化时,arrayLength 会自动更新

3. 使用 Vue 重写的数组方法

适用场景:直接修改数组内容

Vue 对以下 7 个数组方法进行了重写,调用它们会自动触发视图更新:

// 这些方法都会触发响应式更新
this.myArray.push(item)      // 添加元素到末尾
this.myArray.pop()           // 删除末尾元素
this.myArray.shift()         // 删除第一个元素
this.myArray.unshift(item)   // 添加元素到开头
this.myArray.splice(index, 1, item)  // 插入/删除/替换元素
this.myArray.sort()          // 排序
this.myArray.reverse()       // 反转

4. 使用 Vue.set / Vue.delete

适用场景:通过索引直接设置或删除数组元素

// 设置数组元素
Vue.set(this.myArray, index, newValue)
// 或 this.$set(this.myArray, index, newValue)

// 删除数组元素
Vue.delete(this.myArray, index)
// 或 this.$delete(this.myArray, index)

Vue2 修改了数组哪些方法?为什么?

🔧 Vue2 重写的数组方法

Vue2 对以下 7 个数组方法进行了重写:

// 这些方法都会修改原数组
push()    // 添加元素到末尾
pop()     // 删除末尾元素  
shift()   // 删除第一个元素
unshift() // 添加元素到开头
splice()  // 插入/删除/替换元素
sort()    // 排序
reverse() // 反转

🎯 重写原因

核心目的:实现数据的响应式更新

  • Vue2 通过 Object.defineProperty 实现响应式,但它无法直接监听数组的索引和长度变化
  • 因此 Vue2 选择重写了这些会修改原数组的方法,在方法内部添加了通知 Vue 更新视图的逻辑
  • 当调用这些重写后的方法时,Vue 会自动检测到数组变化并更新视图

⚠️ 注意事项

如果使用其他方式(如直接通过索引修改数组元素 this.myArray[index] = newValue),Vue2 无法监听到变化,需要使用 Vue.set()this.$set() 来确保响应式更新。

Vue 父子组件传值的方式

🔗 父子组件通信的 9 种方式

1. Props(推荐

核心机制:父组件通过属性向子组件传递数据

使用方式

  • 父组件:通过 v-bind 绑定属性
  • 子组件:通过 props 接收数据

特点

  • 单向数据流:子组件不能直接修改 props
  • 类型检查:支持数据类型验证和默认值设置
  • 稳定性高:Vue 推荐的标准传值方式

适用场景:绝大多数父子组件数据传递场景

2. 事件($emit)

核心机制:子组件通过事件向父组件传递数据

使用方式

  • 子组件:通过 $emit('eventName', data) 触发事件
  • 父组件:通过 @eventName 监听事件

反向通信(不推荐)

<!-- 父组件 -->
<template>
  <ChildComponent ref="child" />
  <button @click="triggerChild">触发子组件事件</button>
</template>

<script>
export default {
  methods: {
    triggerChild() {
      // 直接向子组件发射事件(不推荐!)
      this.$refs.child.$emit('parent-called', '来自父组件')
    }
  }
}
</script>
<!-- 子组件 -->
<script>
export default {
  mounted() {
    // 监听父组件发射的事件(不推荐!)
    this.$on('parent-called', (data) => {
      console.log('父组件调用我了:', data)
    })
  }
}
</script>

3. v-model(双向绑定)

核心机制:语法糖,结合了 props 和事件

使用方式

<!-- 父组件 -->
<template>
  <ChildComponent v-model="inputValue" />
</template>

<script>
export default {
  data() {
    return {
      inputValue: ''
    }
  }
}
</script>
<!-- 子组件 -->
<template>
  <input :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  props: ['value']
}
</script>

特点

  • ✅ 实现双向数据绑定
  • ✅ 简化代码,提高可读性

适用场景:表单控件、输入组件等需要双向绑定的场景

4. $parent/$children

核心机制:直接访问组件实例

特点

  • 不推荐使用:组件耦合度高,维护困难
  • ❌ 依赖组件层级结构,重构风险大

适用场景:极简单的组件结构,临时调试

5. $refs

核心机制:通过 ref 属性获取组件实例

特点

  • ⚠️ 谨慎使用:直接操作组件实例,破坏组件封装性
  • ⚠️ 在复杂组件结构中容易变得混乱

适用场景:需要直接调用子组件方法的场景

6. $attrs/$listeners

核心机制:传递未声明的 props 和事件

使用方式

<!-- 子组件 -->
<template>
  <div v-bind="$attrs" v-on="$listeners">
    <!-- $attrs 包含所有未声明的 props -->
    <!-- $listeners 包含所有监听的事件 -->
  </div>
</template>

<script>
export default {
  inheritAttrs: false, // 避免将 $attrs 绑定到根元素
  created() {
    console.log(this.$attrs)  // 获取所有非 props 属性
    console.log(this.$listeners) // 获取所有监听的事件
  }
}
</script>

特点

  • ✅ 实现属性和事件的透传
  • ✅ 适用于高阶组件和组件封装

适用场景:组件封装、属性透传

7. provide / inject(依赖注入)

核心机制:祖先组件提供数据,后代组件注入使用

特点

  • ✅ 跨层级组件通信
  • ✅ 减少 props 逐层传递的麻烦

适用场景:跨多级组件的数据共享

8. Vuex/Pinia(状态管理)

核心机制:集中式状态管理

特点

  • ✅ 复杂应用的状态管理
  • ✅ 支持跨组件、跨页面的数据共享
  • ✅ 提供状态追踪和调试工具

适用场景:中大型应用的全局状态管理

9. Event Bus(事件总线)

核心机制:通过事件总线进行任意组件通信

特点

  • ⚠️ 谨慎使用:缺乏状态管理,难以追踪数据流
  • ⚠️ 大型应用中容易造成事件混乱

适用场景:小型应用的跨组件通信

🎯 推荐使用顺序

  1. Props + 事件:Vue 推荐的标准通信方式
  2. v-model:需要双向绑定的场景
  3. provide / inject:跨层级通信
  4. Vuex/Pinia:复杂应用状态管理
  5. 其他方式:仅在特定场景下谨慎使用

Vue 父子组件钩子的执行顺序

📋 核心原则

子组件的生命周期钩子总是在父组件对应钩子之后执行

🔄 标准生命周期执行顺序

1. 加载阶段(Mounting)

父 beforeCreate → 父 created → 父 beforeMount → 
子 beforeCreate → 子 created → 子 beforeMount → 
子 mounted → 
父 mounted

2. 更新阶段(Updating)

父 beforeUpdate → 
子 beforeUpdate → 子 updated → 
父 updated

3. 销毁阶段(Unmounting)

父 beforeDestroy → 
子 beforeDestroy → 子 destroyed → 
父 destroyed

🎯 keep-alive 组件的生命周期

当组件被 keep-alive 包裹时,会使用特殊的生命周期钩子:

1. 组件激活时

父 activated → 子 activated

2. 组件停用时

父 deactivated → 子 deactivated

⚠️ 注意事项

  • 首次渲染:被 keep-alive 包裹的组件会同时触发 mountedactivated
  • 再次激活:仅触发 activated,不会重新触发 mounted
  • 停用:触发 deactivated,但不会立即触发 destroyed
  • 最终销毁:当组件从缓存中移除时才会触发 destroyed

mounted 生命周期和 keep-alive 中 activated 的优先级

🔍 概念解析

  • mounted:组件被首次挂载到 DOM 后触发的钩子函数
  • keep-alive:Vue 内置的抽象组件,用于缓存组件实例,避免重复创建和销毁
  • activated:被 keep-alive 包裹的组件被激活时触发的钩子函数

📊 执行顺序与优先级

场景触发的钩子优先级
首次加载被 keep-alive 包裹的组件mountedactivatedmounted > activated
从缓存中激活组件activated (仅触发)activated 单独执行

🎯 关键结论

触发时机优先级mounted 高于 activated

  • mounted 仅在首次挂载时触发一次
  • activated每次组件被激活时都会触发
  • 当组件被缓存后再次激活,只会触发 activated,不会重新触发 mounted

style 样式添加 scoped 的原因

🛡️ 核心作用

避免样式污染:确保组件样式只作用于当前组件,不影响其他组件

🔧 实现原理

当在 <style> 标签中添加 scoped 属性时:

  1. Vue 会为当前组件的所有 DOM 元素添加一个唯一的属性(如 data-v-xxxxxx
  2. 同时为组件的所有 CSS 选择器自动添加该属性选择器作为后缀
  3. 这样生成的 CSS 规则就只会匹配当前组件的元素

📋 代码示例

<!-- 原始组件 -->
<template>
  <div class="box">Hello Vue</div>
</template>

<style scoped>
.box {
  color: red;
}
</style>

编译后效果

<div class="box" data-v-123456>Hello Vue</div>
.box[data-v-123456] {
  color: red;
}

✅ 优点

  • 防止全局样式污染
  • 避免组件间样式冲突
  • 提高样式的可维护性
  • 支持组件样式的模块化开发

以上就是 Vue 重点知识复习(一)的全部内容,涵盖了对 Vue 的理解、Vue 与 React 的区别、Vue2 与 Vue3 的区别、数组变化检测、父子组件传值方式、生命周期执行顺序等核心知识点。希望对你的 Vue 学习有所帮助!