对 Vue 的理解
💡 核心定位:Vue 是一个渐进式的 JavaScript 框架,专注于构建用户界面。
核心思想
- 数据驱动:通过数据变化自动更新视图
- 组件化:将页面拆分成独立组件,提高代码复用性和可维护性
主要优势
- ✅ 简单易用:模板语法易于理解和学习,可以快速构建交互式的 Web 应用程序
- ✅ 灵活性高:支持多种开发模式和项目规模
- ✅ 性能优越:高效的虚拟 DOM 和渲染机制
- ✅ 扩展性强:丰富的官方插件(Vuex/Pinia、Vue Router 等)
核心特征
响应式数据绑定是 Vue 最核心的特性之一:
- 通过对数据进行劫持和监听实现双向绑定
- 数据变化自动更新视图,视图变化反映到数据
- 清晰可预测的数据流,减少开发工作量
总之,Vue 平衡了灵活性与规范性,组件化设计促进了代码复用,响应式系统简化了状态管理,渐进式架构适应了不同工程需求,活跃的生态覆盖完整开发链路,是一个值得深入学习和使用的框架。
Vue 和 React 的区别
📊 核心区别对比
| 对比维度 | Vue | React |
|---|---|---|
| 模板语法 | 基于 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(事件总线)
核心机制:通过事件总线进行任意组件通信
特点:
- ⚠️ 谨慎使用:缺乏状态管理,难以追踪数据流
- ⚠️ 大型应用中容易造成事件混乱
适用场景:小型应用的跨组件通信
🎯 推荐使用顺序
- Props + 事件:Vue 推荐的标准通信方式
- v-model:需要双向绑定的场景
- provide / inject:跨层级通信
- Vuex/Pinia:复杂应用状态管理
- 其他方式:仅在特定场景下谨慎使用
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 包裹的组件会同时触发
mounted和activated - 再次激活:仅触发
activated,不会重新触发mounted - 停用:触发
deactivated,但不会立即触发destroyed - 最终销毁:当组件从缓存中移除时才会触发
destroyed
mounted 生命周期和 keep-alive 中 activated 的优先级
🔍 概念解析
- mounted:组件被首次挂载到 DOM 后触发的钩子函数
- keep-alive:Vue 内置的抽象组件,用于缓存组件实例,避免重复创建和销毁
- activated:被 keep-alive 包裹的组件被激活时触发的钩子函数
📊 执行顺序与优先级
| 场景 | 触发的钩子 | 优先级 |
|---|---|---|
| 首次加载被 keep-alive 包裹的组件 | mounted → activated | mounted > activated |
| 从缓存中激活组件 | activated (仅触发) | activated 单独执行 |
🎯 关键结论
触发时机优先级:mounted 高于 activated
mounted仅在首次挂载时触发一次activated在每次组件被激活时都会触发- 当组件被缓存后再次激活,只会触发
activated,不会重新触发mounted
style 样式添加 scoped 的原因
🛡️ 核心作用
避免样式污染:确保组件样式只作用于当前组件,不影响其他组件
🔧 实现原理
当在 <style> 标签中添加 scoped 属性时:
- Vue 会为当前组件的所有 DOM 元素添加一个唯一的属性(如
data-v-xxxxxx) - 同时为组件的所有 CSS 选择器自动添加该属性选择器作为后缀
- 这样生成的 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 学习有所帮助!