vue+ts 基础面试题 (一 )

目录

1.Vue3 响应式原理

一、 响应式的基本概念

二、 核心机制:Proxy 和依赖追踪

三、 触发更新的过程

四、 代码示例

五、 优势总结

2.如何实现组件间通信?

一、父子组件通信

1. 父传子:Props 传递

2. 子传父:自定义事件

二、兄弟组件通信

1. 通过共同父组件中转

2. 事件总线(Event Bus)

三、跨层级通信

1. Provide/Inject(依赖注入)

2. 全局状态管理(Vuex/Pinia)

四、特殊场景方案

1.$refs 直接访问(慎用)

2.$attrs/$listeners(透传特性)

五、通信方式对比

六、实际案例参考:

3.Composition 的生命周期钩子

一、主要生命周期钩子函数

1.onBeforeMount()

2.onMounted()

3.onBeforeUpdate()

4.onUpdated()

5.onBeforeUnmount()

6.onUnmounted()

7.onErrorCaptured()

二、使用注意事项

三、代码示例

4.Composition API vs Options API

一、Options API(选项式 API)

1. 特点:

2. 示例代码:

3.优点:

4.缺点:

二、 Composition API(组合式 API)

1. 特点:

2. 示例代码:

3. 优点:

4. 缺点:

三、核心对比

四、使用场景:

5.setup() 函数作用

一、 核心作用

二、关键注意事项

6.ref 和 reactive 的区别

一、基本定义

二、主要区别

三、示例

四、使用场景

7.Props 传递机制

一、基本概念

二、 在子组件中声明 Props

声明方式:

Options API:

Composition API:

三、在父组件中传递 Props

示例:

四、 Props 的类型验证和默认值

示例:

五、单向数据流原则

六、高级用法

8.自定义事件 (emit)

一、在子组件中定义和触发事件

二、 在父组件中监听事件

三、注意事项

9.生命周期钩子对比

一、生命周期阶段与钩子对照表

二、关键变化说明

1.重命名的钩子

2.Composition API 特性

3.新增调试钩子

三、执行顺序对比(同一组件)

10.watch 和 watchEffect 的区别?

一、 基本概念

二、主要区别

三、示例

四、适用场景总结

1.watch 

2.watchEffect 


1.Vue3 响应式原理

Vue3 的响应式原理是其核心特性之一,它允许数据变化时自动更新视图。相比 Vue2,Vue3 使用了 JavaScript 的 Proxy 对象来实现更高效和灵活的响应式系统。下面我将逐步解释其工作机制,帮助你理解整个过程。

一、 响应式的基本概念

  • 响应式系统确保当数据(如变量或对象属性)发生变化时,依赖该数据的视图或计算逻辑自动更新。这类似于数学中的函数依赖关系:如果 $y = f(x)$,那么当 $x$ 改变时,$y$ 应自动重新计算。
  • Vue3 的核心是创建一个响应式代理对象,它会拦截对数据的访问(get)和修改(set)操作,从而追踪依赖并触发更新。

二、 核心机制:Proxy 和依赖追踪

  • Proxy 对象:Vue3 使用 JavaScript 的 Proxy API 来包装原始数据。Proxy 可以定义“陷阱”(traps),如 getset,用于拦截操作。
    • 当访问属性时(如 obj.a),get 陷阱被触发,系统记录当前依赖(例如一个渲染函数)。
    • 当修改属性时(如 obj.a = 1),set 陷阱被触发,系统通知所有依赖进行更新。
  • 依赖追踪:Vue3 通过一个全局的“依赖收集器”来管理依赖关系。每个响应式属性都关联一个依赖集合(称为 Dep),当属性被访问时,当前运行的“effect”函数(如组件的渲染函数)会被添加到这个集合中。
    • 这可以用一个简单的数学关系表示:假设有一个响应式对象 $data$,其属性 $x$ 的依赖集合为 $D_x$。当 $x$ 改变时,系统遍历 $D_x$ 并执行每个 effect 函数。
    • 公式表示:如果 $effect \in D_x$,那么 $x$ 变化时 $effect()$ 被调用。

三、 触发更新的过程

  • 当数据被修改时,Proxy 的 set 陷阱会执行以下步骤:
  1. 更新原始数据值。
  2. 通知依赖集合:遍历所有依赖的 effect 函数,并调用它们。
  3. 如果 effect 函数涉及计算属性(如 $computed = x + y$),系统会重新计算这些值。
  • 优势:Proxy 支持深层嵌套对象和数组的响应式,无需像 Vue2 那样递归遍历整个对象,这提高了性能。

四、 代码示例

下面是一个简化版的 Vue3 响应式实现,使用 JavaScript 代码演示核心逻辑。注意,实际 Vue3 源码更复杂,但这里聚焦基本原理。

// 创建一个响应式对象
function reactive(target) {return new Proxy(target, {get(obj, key) {track(obj, key); // 追踪依赖:记录当前 effect 函数return obj[key];},set(obj, key, value) {obj[key] = value;trigger(obj, key); // 触发更新:通知所有依赖return true;}});
}// 依赖收集和触发函数(简化版)
const depsMap = new Map(); // 存储每个对象的依赖映射function track(target, key) {let dep = depsMap.get(target);if (!dep) {dep = new Map();depsMap.set(target, dep);}let effects = dep.get(key);if (!effects) {effects = new Set();dep.set(key, effects);}if (currentEffect) {effects.add(currentEffect); // 添加当前 effect 到依赖集合}
}function trigger(target, key) {const dep = depsMap.get(target);if (dep) {const effects = dep.get(key);if (effects) {effects.forEach(effect => effect()); // 执行所有依赖的 effect 函数}}
}// 定义一个 effect 函数(例如组件的渲染逻辑)
let currentEffect = null;
function effect(fn) {currentEffect = fn;fn(); // 首次执行,触发依赖收集currentEffect = null;
}// 使用示例
const state = reactive({ count: 0 });effect(() => {console.log(`Count is: ${state.count}`); // 依赖 state.count
});state.count = 1; // 输出:Count is: 1(自动触发更新)

五、 优势总结

  • 高效性:Proxy 直接拦截操作,避免了 Vue2 中递归定义 getter/setter 的开销,支持动态添加属性。
  • 灵活性:可以处理数组索引变化、Map/Set 等复杂数据结构。
  • 可组合性:Vue3 的 reactiveref API 使状态管理更模块化。
  • 数学上,这类似于一个动态的依赖图:每个响应式属性是一个节点,依赖关系是边,变化时沿边传播更新。

2.如何实现组件间通信?

实现组件间通信是前端开发中的核心问题,不同框架有各自的解决方案。以下是主流的通信方式及代码示例:

一、父子组件通信

1. 父传子:Props 传递
// 父组件
<Child :message="parentData" />// 子组件
export default {props: ['message'],mounted() {console.log(this.message) // 接收父组件数据}
}
2. 子传父:自定义事件
// 子组件
this.$emit('child-event', data) // 触发事件// 父组件
<Child @child-event="handleEvent" />methods: {handleEvent(data) {console.log(data) // 接收子组件数据}
}

二、兄弟组件通信

1. 通过共同父组件中转
// 父组件
<ChildA @send="receiveData" />
<ChildB :data="sharedData" />data() {return { sharedData: null }
},
methods: {receiveData(data) {this.sharedData = data // 中转数据}
}
2. 事件总线(Event Bus)
// 创建事件中心
const bus = new Vue()// 组件A(发送)
bus.$emit('update', data)// 组件B(接收)
bus.$on('update', data => {console.log(data)
})

三、跨层级通信

1. Provide/Inject(依赖注入)
// 祖先组件
provide() {return { theme: 'dark' }
}// 后代组件(任意层级)
inject: ['theme'],
mounted() {console.log(this.theme) // 输出 'dark'
}
2. 全局状态管理(Vuex/Pinia)
// store.js
export default new Vuex.Store({state: { count: 0 },mutations: {increment(state) {state.count++}}
})// 任意组件
this.$store.commit('increment')
console.log(this.$store.state.count)

四、特殊场景方案

1.$refs 直接访问(慎用)
<Child ref="childComp" />methods: {callChild() {this.$refs.childComp.childMethod()}
}
2.$attrs/$listeners(透传特性)
// 父组件
<Child :title="pageTitle" @close="handleClose" />// 中间组件
<Grandchild v-bind="$attrs" v-on="$listeners" />

五、通信方式对比

方式适用场景优点缺点
Props/Events父子组件简单直接层级深时繁琐
Event Bus任意组件解耦灵活难以追踪事件源
Vuex/Pinia中大型应用集中管理,调试工具完善增加项目复杂度
Provide/Inject深层嵌套组件避免逐层传递数据非响应式(需处理)

最佳实践建议

  1. 优先使用 Props/Events 处理父子通信
  2. 跨层级使用 Provide/Inject 替代多级 Props
  3. 复杂应用采用 Vuex/Pinia 管理全局状态
  4. 避免过度使用 $refs 和事件总线,防止代码混乱

六、实际案例参考:

// 使用Pinia状态管理
// store/counter.js
export const useCounterStore = defineStore('counter', {state: () => ({ count: 0 }),actions: {increment() {this.count++}}
})// 组件A
import { useCounterStore } from '@/store/counter'
const store = useCounterStore()
store.increment() // 组件B
const store = useCounterStore()
console.log(store.count) // 实时获取最新值

3.Composition 的生命周期钩子

在 Vue.js 的 Composition API 中,生命周期钩子提供了一种在组件不同阶段(如创建、更新、销毁)执行自定义逻辑的方式。与 Options API 不同,Composition API 使用函数式钩子(如 onMountedonUnmounted),这些钩子需要在 setup() 函数或 <script setup> 语法中导入和使用。下面我将逐步解释主要钩子及其用法。

一、主要生命周期钩子函数

Composition API 提供了以下核心钩子,每个钩子对应组件生命周期的特定阶段:

1.onBeforeMount()
  • 用途:在组件挂载到 DOM 之前调用。适合执行初始化操作,如设置状态或获取数据。
  • 触发时机:在 setup() 函数运行后,组件首次渲染前。
2.onMounted()
  • 用途:在组件挂载到 DOM 后调用。常用于访问 DOM 元素、发起 API 请求或设置事件监听器。
  • 触发时机:组件首次渲染完成。
3.onBeforeUpdate()
  • 用途:在组件更新之前调用。适合在状态变化前执行清理或验证逻辑。
  • 触发时机:响应式数据变化后,DOM 更新前。
4.onUpdated()
  • 用途:在组件更新后调用。用于处理更新后的 DOM 操作或状态同步。
  • 触发时机:DOM 重新渲染完成后。
5.onBeforeUnmount()
  • 用途:在组件卸载之前调用。适合执行清理工作,如移除事件监听器或取消定时器。
  • 触发时机:组件销毁流程开始前。
6.onUnmounted()
  • 用途:在组件卸载后调用。用于最终资源释放,如断开网络连接或清除缓存。
  • 触发时机:组件从 DOM 中移除后。
7.onErrorCaptured()
  • 用途:捕获子组件或当前组件的错误。用于错误处理或日志记录。
  • 触发时机:组件树中任何地方抛出错误时。

二、使用注意事项

  • 执行顺序:钩子按生命周期顺序执行,例如:onBeforeMountonMountedonBeforeUpdateonUpdatedonBeforeUnmountonUnmounted
  • 依赖导入:所有钩子需从 vue 包导入,并在 setup() 函数内调用。
  • 异步支持:钩子回调可以是异步函数,适用于数据获取等操作。
  • 性能优化:避免在频繁更新的钩子(如 onUpdated)中执行重操作,以防止性能问题。

三、代码示例

以下是一个简单的 Vue 3 组件示例,展示如何使用 Composition API 的生命周期钩子:

<template><div>{{ message }}</div>
</template><script>
import { ref, onMounted, onUnmounted } from 'vue';export default {setup() {const message = ref('组件加载中...');// 挂载后更新消息onMounted(() => {message.value = '组件已挂载!';console.log('DOM 已渲染');});// 卸载时清理资源onUnmounted(() => {console.log('组件已卸载');});return { message };}
};
</script>

4.Composition API vs Options API

在 Vue.js 开发中,Composition APIOptions API 是两种不同的组件代码组织方式。以下是它们的核心区别和适用场景分析:


一、Options API(选项式 API)

1. 特点
  • 通过预设选项(如 data, methods, computed)组织代码
  • 逻辑分散在不同选项中,相同功能可能跨多个选项
  • 适合简单场景,学习曲线平缓
2. 示例代码
export default {data() {return { count: 0 }},methods: {increment() {this.count++}},computed: {doubleCount() {return this.count * 2}}
}
3.优点
  • 结构清晰直观,适合新手
  • 选项隔离降低耦合度
  • 兼容性好(Vue 2/3 均支持)
4.缺点
  • 复杂组件中逻辑碎片化
  • 代码复用依赖 mixins(易命名冲突)

二、 Composition API(组合式 API)

1. 特点
  • 通过 setup() 函数集中管理逻辑
  • 基于函数组合(如 ref, reactive, computed
  • 逻辑按功能聚合,而非选项类型
2. 示例代码
import { ref, computed } from 'vue'export default {setup() {const count = ref(0)const doubleCount = computed(() => count.value * 2)function increment() {count.value++}return { count, doubleCount, increment }}
}
3. 优点
  • 逻辑高内聚,复杂组件更易维护
  • 更好的 TypeScript 支持
  • 灵活的逻辑复用(自定义 Hook)
  • 代码更精简(减少 this 依赖)
4. 缺点
  • 学习曲线较陡峭(需理解响应式原理)
  • 过度集中可能降低可读性

三、核心对比

维度Options APIComposition API
代码组织按选项类型分散按功能逻辑集中
逻辑复用Mixins(易冲突)自定义 Hook(解耦性强)
TS 支持有限完整类型推断
适用场景简单组件/新手项目复杂逻辑/大型应用
响应式数据通过 data() 返回通过 ref()/reactive() 声明

四、使用场景:

Options API :项目简单或团队 Vue 经验较少,需要快速迭代原型,维护旧版 Vue 2 项目

Composition API:组件逻辑复杂(如状态管理、异步流程),需要高度复用逻辑(自定义 Hook),使用 TypeScript 开发,长期维护的大型项目

5.setup() 函数作用

一、 核心作用

  • setup()函数主要用于初始化程序环境,包括设置变量初始值、配置硬件参数、定义画布大小等。
  • 它只在程序执行时调用一次,之后不再运行

二、关键注意事项

  • 执行时机:setup()只在程序启动时运行一次
  • 必要性:在支持setup()的框架中,它是必须定义的函数(即使为空),否则程序可能报错
  • 常见错误:如果在setup()外部放置初始化代码,可能导致未定义行为或性能问题

6.refreactive 的区别

一、基本定义

  • ref: 用于创建一个响应式引用,适用于基本类型(如数字、字符串、布尔值)或对象。它返回一个带有 .value 属性的对象,访问或修改数据需要通过 .value
  • reactive: 用于创建一个响应式对象,适用于对象或数组。它直接返回一个代理对象,属性可以直接访问和修改,无需额外语法。

二、主要区别

方面refreactive
适用类型更适合基本类型(如 number, string),也可用于对象。仅适用于对象或数组,不适用于基本类型。
访问方式必须通过 .value 访问或修改数据(例如 myRef.value)。直接访问属性(例如 myReactive.key),无需 .value
模板使用在模板中自动解包,无需写 .value(Vue 内部处理)。在模板中直接使用属性名,行为更直观。
内部实现包装一个值,使用 Object.defineProperty 或 Proxy 实现响应式。基于 Proxy 代理整个对象,深度监听嵌套属性。
解构问题解构后仍保留响应性(因为返回的是引用对象)。解构对象会丢失响应性,需使用 toRefs 辅助函数保持。
重新赋值可以重新赋值整个对象(通过 myRef.value = newValue)。不能直接重新赋值整个对象;需修改属性或使用 Object.assign

三、示例

import { ref, reactive } from 'vue';// 使用 ref 示例
const countRef = ref(0); // 基本类型
console.log(countRef.value); // 输出: 0
countRef.value = 10; // 修改值const userRef = ref({ name: 'Alice', age: 30 }); // 对象类型
console.log(userRef.value.name); // 输出: 'Alice'// 使用 reactive 示例
const userReactive = reactive({ name: 'Bob', age: 25 }); // 对象类型
console.log(userReactive.name); // 输出: 'Bob',无需 .value
userReactive.age = 26; // 直接修改属性// 解构问题演示
const { age } = userReactive; // 解构会丢失响应性
// 正确方式:使用 toRefs 保持响应性
const { name, age: reactiveAge } = toRefs(userReactive);

四、使用场景

ref:处理基本类型数据,需要频繁重新赋值整个对象 

reactive :处理复杂对象或嵌套数据结构,需要直接访问属性,避免写 .value 的模板代码

总结:

  • reactive 管理状态对象,用 ref 处理独立的基本值
  • 选择时考虑数据结构和代码可读性:简单值用 ref,复杂对象用 reactive

7.Props 传递机制

一、基本概念

  • Props 允许父组件将数据“注入”到子组件中,子组件通过声明 Props 来接收这些数据。
  • 数据流是单向的:父组件更新 Props 会触发子组件重新渲染,但子组件不能直接修改 Props
  • 用途:适用于配置子组件、传递静态或动态数据,例如传递用户信息、配置选项等。

二、 在子组件中声明 Props

子组件需要显式声明它可以接收的 Props。这通常在组件的选项或 Composition API 中完成。

  • 声明方式
    • 使用 props 选项(Options API)或 defineProps 宏(Composition API)。
    • 每个 Prop 可以指定类型、默认值和验证规则。
  • Options API:
    // 子组件 (ChildComponent.vue)
    export default {props: {// 基本类型声明,例如字符串title: String,// 带默认值的数字类型count: {type: Number,default: 0},// 必填的布尔类型isActive: {type: Boolean,required: true}}
    }
    
    Composition API:
    // 子组件 (ChildComponent.vue)
    import { defineProps } from 'vue'const props = defineProps({title: String,count: { type: Number, default: 0 },isActive: { type: Boolean, required: true }
    })
    

三、在父组件中传递 Props

  • 静态传递:直接传递固定值。
  • 动态传递:绑定到父组件的数据或计算属性,实现响应式更新。
示例
<!-- 父组件模板 -->
<template><ChildComponenttitle="欢迎使用 Vue 3"  <!-- 静态字符串 -->:count="parentCount"     <!-- 动态绑定数字 -->:is-active="isActive"   <!-- 动态绑定布尔值 -->/>
</template><script>
import ChildComponent from './ChildComponent.vue'export default {components: { ChildComponent },data() {return {parentCount: 10,      // 父组件数据isActive: true}}
}
</script>

四、 Props 的类型验证和默认值

  • 类型:可以指定为原生类型(如 String, Number, Boolean, Array, Object)或自定义类型。
  • 默认值:通过 default 属性设置,当父组件未传递 Prop 时使用。
  • 验证:使用 validator 函数进行自定义验证
示例
props: {age: {type: Number,default: 18,validator: (value) => value >= 0  // 验证年龄非负}
}

五、单向数据流原则

  • Props 是只读的:子组件不能直接修改接收到的 Prop。如果需要基于 Prop 派生数据,应使用计算属性。
  • 原因:确保数据源单一,避免父子组件间的循环更新。
    // 子组件中错误做法:直接修改 Prop
    // this.count = 20  // 不允许,会触发警告// 正确做法:使用计算属性或本地数据
    computed: {doubledCount() {return this.count * 2  // 基于 Prop 派生新值}
    }
    

六、高级用法

  • 传递对象或数组:使用 v-bind 传递整个对象,子组件通过 Prop 接收。
    <!-- 父组件 -->
    <ChildComponent :user-info="{ name: '张三', age: 30 }" />
    
  • Prop 命名约定:建议使用 camelCase 声明,但在模板中使用 kebab-case(HTML 属性不区分大小写)。例如,声明为 userInfo,传递时用 user-info
  • 响应式更新:父组件数据变化时,子组件的 Prop 会自动更新(得益于 Vue 的响应式系统)。

8.自定义事件 (emit)

一、在子组件中定义和触发事件

  • 使用 defineEmits 声明事件列表。
  • 在方法中调用 emit 函数触发事件,并传递数据。
  • 在模板中绑定事件触发器(如按钮点击)。
//子组件 ChildComponent.vue
<script setup>
// 导入 defineEmits
import { defineEmits } from 'vue';// 定义事件列表:声明一个名为 'customEvent' 的事件
const emit = defineEmits(['customEvent']);// 定义一个方法,在触发时发送事件
function handleClick() {// 触发 'customEvent' 事件,并传递数据(例如字符串 'Hello from child!')emit('customEvent', 'Hello from child!');
}
</script><template><!-- 在按钮点击时调用 handleClick 方法 --><button @click="handleClick">触发自定义事件</button>
</template>

二、 在父组件中监听事件

  • 导入子组件。
  • 在模板中使用 @event-namev-on:event-name 监听事件。
  • 定义一个回调函数来处理事件数据。
//父组件 ParentComponent.vue
<script setup>
// 导入子组件
import ChildComponent from './ChildComponent.vue';// 定义回调函数,接收子组件传递的数据
function onCustomEvent(data) {console.log('事件触发!数据:', data); // 输出:事件触发!数据: Hello from child!// 这里可以添加业务逻辑,例如更新父组件状态
}
</script><template><!-- 监听子组件的 'customEvent' 事件,并绑定回调函数 --><ChildComponent @customEvent="onCustomEvent" />
</template>

三、注意事项

  • 事件命名规范:推荐使用 kebab-case(短横线分隔)命名事件,如 custom-event,以保持与 HTML 属性一致。在模板中监听时使用 @custom-event,但在 defineEmits 中声明时使用 camelCase(如 customEvent)。
  • 数据传递emit 可以传递多个参数,例如 emit('event', arg1, arg2),父组件回调函数接收这些参数。
  • TypeScript 支持:如果使用 TypeScript,可以通过泛型定义事件类型:
    <script setup lang="ts">
    const emit = defineEmits<{(event: 'customEvent', data: string): void;
    }>();
    </script>
    
  • 错误处理:确保事件名一致,避免拼写错误。如果父组件未监听事件,子组件的 emit 不会报错,但也不会执行任何操作。
  • 替代方案:对于简单场景,也可以使用 Props 传递数据,但自定义事件更适合子组件主动通知父组件的场景。

9.生命周期钩子对比

Vue 3 的生命周期钩子在 Options APIComposition API 中有不同实现方式,同时部分钩子名称与 Vue 2 有差异。以下是核心对比:

生命周期阶段与钩子对照表

阶段Vue 2 (Options)Vue 3 (Options API)Vue 3 (Composition API)
初始化beforeCreatebeforeCreate无(逻辑在 setup() 内)
createdcreated无(逻辑在 setup() 内)
挂载前beforeMountbeforeMountonBeforeMount
挂载完成mountedmountedonMounted
更新前beforeUpdatebeforeUpdateonBeforeUpdate
更新完成updatedupdatedonUpdated
卸载前beforeDestroybeforeUnmountonBeforeUnmount
卸载完成destroyedunmountedonUnmounted
缓存组件activatedactivatedonActivated
deactivateddeactivatedonDeactivated
错误捕获errorCapturederrorCapturedonErrorCaptured
调试钩子onRenderTracked
onRenderTriggered

关键变化说明

1.重命名的钩子
  1. beforeDestroybeforeUnmount(更准确描述组件卸载行为)
  2. destroyedunmounted(语义更清晰)
2.Composition API 特性
  • 所有钩子以 onXxx 形式导入(如 onMounted
  • beforeCreatecreatedsetup() 替代:
    import { onMounted } from 'vue';export default {setup() {// 替代 created 逻辑console.log("初始化逻辑");onMounted(() => {console.log("组件已挂载");});}
    }
    
3.新增调试钩子
  • onRenderTracked:追踪响应式依赖
  • onRenderTriggered:诊断重新渲染原因

执行顺序对比(同一组件)

Options API: beforeCreate → created → beforeMount → mounted → beforeUpdate → updated → beforeUnmount → unmountedComposition API:setup() → onBeforeMount → onMounted → onBeforeUpdate → onUpdated → onBeforeUnmount → onUnmounted

最佳实践建议

  • 新项目优先使用 Composition API,逻辑更聚合
  • 迁移项目可逐步替换重命名钩子(如 beforeDestroybeforeUnmount
  • 调试响应式问题时使用 onRenderTracked/onRenderTriggered

10.watchwatchEffect 的区别?

一、 基本概念

  • watch: 用于显式观察一个或多个响应式数据源(如 ref、reactive 对象、函数等),并在其变化时执行回调函数。它允许你指定依赖项,并控制监听行为(如深度监听或立即执行)。
  • watchEffect: 自动跟踪其函数体内部的响应式依赖项,并在任何依赖变化时重新运行该函数。它类似于计算属性(computed),但用于执行副作用(如 DOM 操作、API 调用),而非返回一个值。

二、主要区别

特性watchwatchEffect
依赖项指定方式需要显式声明依赖源(如 () => data.value)。自动收集函数体中的所有响应式依赖项。
初始执行行为默认不立即执行回调;可通过 { immediate: true } 选项启用。在创建时立即执行一次函数体。
访问旧值/新值回调函数可接收旧值和新值作为参数(如 (newVal, oldVal) => {})。无法直接访问旧值;只提供当前值。
深度监听支持支持 { deep: true } 选项进行深度监听(如对象嵌套属性)。默认深度监听所有依赖项,无需额外选项。
适用场景适合精确控制监听逻辑,如当特定数据变化时触发操作。适合自动响应依赖变化,如执行副作用或初始化任务。
停止监听通过返回的停止函数手动停止(如 const stop = watch(...); stop())。同样通过返回的停止函数手动停止。

三、示例

import { ref, reactive, watch, watchEffect } from 'vue';export default {setup() {const count = ref(0);const user = reactive({ name: 'Alice', age: 25 });// 示例 1: 使用 watchwatch(// 显式指定依赖源:count 和 user.name[() => count.value, () => user.name],// 回调函数接收新值和旧值([newCount, newName], [oldCount, oldName]) => {console.log('watch - count 变化:', newCount, '旧值:', oldCount);console.log('watch - name 变化:', newName, '旧值:', oldName);},// 选项:立即执行和深度监听{ immediate: true, deep: true });// 示例 2: 使用 watchEffectwatchEffect(() => {// 自动跟踪 count.value 和 user.ageconsole.log('watchEffect - count:', count.value);console.log('watchEffect - age:', user.age);// 注意:这里无法访问旧值});// 修改数据以触发监听setTimeout(() => {count.value = 1; // 触发 watch 和 watchEffectuser.name = 'Bob'; // 触发 watchuser.age = 26; // 触发 watchEffect}, 1000);return { count, user };}
};

四、适用场景总结

1.watch 
  • 你需要精确控制监听哪些数据源。
  • 需要访问变化前后的值(如比较旧值和新值)。
  • 场景示例:表单验证(当特定字段变化时检查)、API 请求(当 ID 变化时重新获取数据)。
2.watchEffect 
  • 依赖项复杂或动态,希望自动跟踪所有响应式引用。
  • 需要立即执行副作用(如初始化日志或设置事件监听器)。
  • 场景示例:实时日志输出、自动清理资源(结合 onInvalidate 函数)。

如果依赖项明确且需要旧值,用 watch;如果依赖项动态或需要简化代码,用 watchEffect

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917663.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring AI实战:SpringBoot项目结合Spring AI开发——提示词(Prompt)技术与工程实战详解

&#x1fa81;&#x1f341; 希望本文能给您带来帮助&#xff0c;如果有任何问题&#xff0c;欢迎批评指正&#xff01;&#x1f405;&#x1f43e;&#x1f341;&#x1f425; 文章目录一、前言二、提示词前置知识2.1 提示词要素2.2 设计提示词的通用技巧2.2.1 从简单开始2.2.…

【后端】Java static 关键字详解

在 Java 中&#xff0c;static 是一个修饰符&#xff0c;用于定义与类相关&#xff08;而非对象实例相关&#xff09;的成员。以下是核心知识点和用法&#xff1a;一、四大用途静态变量&#xff08;类变量&#xff09; 作用&#xff1a;属于类&#xff0c;而非实例。所有实例共…

算法训练营DAY50 第十一章:图论part01

98. 所有可达路径 98. 所有可达路径 【题目描述】 给定一个有 n 个节点的有向无环图&#xff0c;节点编号从 1 到 n。请编写一个程序&#xff0c;找出并返回所有从节点 1 到节点 n 的路径。每条路径应以节点编号的列表形式表示。 【输入描述】 第一行包含两个整数 N&#…

OpenCV:从入门到实战的全方位指南

目录 一、OpenCV 简介 &#xff08;一&#xff09;特点 &#xff08;二&#xff09;应用场景 二、OpenCV 的核心模块 &#xff08;一&#xff09;core 模块 &#xff08;二&#xff09;imgproc 模块 &#xff08;三&#xff09;video 模块 &#xff08;四&#xff09;f…

如何在 Ubuntu 24.04 上安装和配置 TFTP 服务器

了解如何在 Ubuntu 24.04 Linux 上安装 TFTP 以执行基本的文件传输。 简单文件传输协议(TFTP)是标准 FTP 的轻量级替代方案,用于在联网设备之间传输文件。与 FTP 和 HTTP 相比,TFTP 更简单,无需复杂的客户端-服务器模型即可操作。这就是为什么该协议用于执行基本文件传输…

基于 AXI-Lite 实现可扩展的硬件函数 RPC 框架(附完整源码)

AXI-Lite 实现RPC调用硬件函数服务 &#x1f44b; 本文介绍如何基于 AXI-Lite 总线设计一个通用的“硬件函数调用框架”。主机端&#xff08;PS&#xff09;只需通过寄存器写入参数与启动标志&#xff0c;即可触发 PL 模块执行指定算法逻辑&#xff0c;并将结果返回。 该机制本…

[spring-cloud: NamedContextFactory ClientFactoryObjectProvider]-源码阅读

依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-commons</artifactId><version>4.3.0</version> </dependency>源码 NamedContextFactory NamedContextFactory 类通过创建多个子…

HBase MOB技术特点及使用场景介绍

在 HBase 2.0 版本之前,虽然 HBase 能够存储从 1 字节到 10MB 大小的二进制对象 ,但其读写路径主要针对小于 100KB 的值进行了优化。当面对大量大小在 100KB - 10MB 之间的数据时,传统的存储方式就会暴露出问题。例如,当存储大量的图片、文档或短视频等中等大小对象时,由于…

Ubuntu 配置密钥+密码登录

目录 1、密钥生成 2、发送公钥至 需要连接的服务器 3、选用私钥登录 1、密钥生成 ssh-keygen -t rsa -b 4096 -C "angindem"2、发送公钥至 需要连接的服务器 将.ssh中的id_rsa.pub 的密钥&#xff0c;放在authorized_keys中 注意&#xff1a;.ssh 文件夹一定赋予…

谷歌浏览器Chrome 缓存迁移

步骤 1&#xff1a;准备数据迁移1. 关闭 Chrome 及所有后台进程在任务管理器&#xff08;CtrlShiftEsc&#xff09;中结束所有 chrome.exe 进程。 2. 备份并移动原数据- 将 C:\Users\xxx\AppData\Local\Google\Chrome\User Data **整个文件夹**复制到新位置&#xff08;如 G:\…

Java中的RabbitMQ完全指南

Java中的RabbitMQ完全指南 1. 引言 什么是RabbitMQ RabbitMQ是一个开源的消息代理和队列服务器&#xff0c;实现了高级消息队列协议&#xff08;AMQP&#xff09;。它充当应用程序之间的消息中间件&#xff0c;允许分布式系统中的不同组件进行异步通信。RabbitMQ使用Erlang语言…

【MCAL】AUTOSAR架构下SPI数据异步DMA收发具体实现

目录 前言 正文 1.依赖的硬件特性 1.1.SPI硬件特性 1.1.1. TXFIFO Single Move Mode 1.1.2. RXFIFO Single Move Mode 1.1.3. Move Counter模式 1.1.4. PT中断 1.2.IR硬件特性 1.3.DMA硬件特性 1.3.1. DMA通道硬件请求 1.3.2. DMA循环Buffer 1.3.3. DMA Link List …

【Unity】协程 Async

协程 协程是 Unity 内置的异步机制&#xff0c;通过 yield 暂停执行&#xff0c;实现任务在多帧中分段执行。与普通函数不同&#xff0c;协程可在执行过程中挂起和恢复&#xff0c;呈现"并发"效果&#xff0c;但本质上仍运行于主线程。若在协程中进行耗时操作&#…

《揭秘!10 分钟洞悉 Prompt、Function Calling、MCP 与 AI agent 奥秘》

Prompt、Function Calling、MCP、AI agent这些术语频繁闯入我们的视野&#xff0c;它们到底都是什么、有啥关系。只需十分钟&#xff0c;咱们抽丝剥茧&#xff0c;揭开它们的神秘面纱&#xff0c;轻松掌握这些关键概念 并了解AI agent 完整执行流程。 一、提示词&#xff08;P…

决策树(回归树)全解析:原理、实践与应用

文章目录一、概述1.1 介绍1.2 回归树和分类树区别二、重要参数、属性及接口2.1 criterion&#xff08;不纯度衡量指标&#xff09;2.2 回归树如何工作&#xff08;核心流程拆解&#xff09;三、用回归树拟合正弦曲线&#xff08;实战案例&#xff09;3.1 绘制正弦曲线3.2 为正弦…

【盘古100Pro+开发板实验例程】FPGA学习 | HDMI 回环实验

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 1. 实验简介 实验目的&#xff1a; 完成 HDMI 回环实验 实验环境&#xff1a; Window11 PDS2022.2-SP6.4 硬件环境…

鸿蒙系统PC安装指南

鸿蒙系统PC安装指南一、安装DevEco Studio集成开发环境二、下载鸿蒙系统PC三、启动鸿蒙系统及使用一、安装DevEco Studio集成开发环境首先访问华为官网上&#xff0c;注册并登录华为账号&#xff0c;以开始下载所需的软件。若尚未注册&#xff0c;请先注册一个。在官网页面中&a…

三十九、【扩展工具篇】Allpairspy 组合用例生成器:智能设计高效测试集

三十九、【扩展工具篇】Allpairspy 组合用例生成器:智能设计高效测试集 前言 准备工作 第一部分:后端实现 - `allpairspy` API 1. 创建 `allpairspy` 服务 2. 创建 `allpairspy` API 视图 3. 注册 API 路由 第二部分:前端实现 - `Allpairspy` 工具界面 1. 创建 API 服务 (`s…

ZooKeeper 深度实践:从原理到 Spring Boot 全栈落地

在 Kubernetes 为主流注册发现的今天&#xff0c;给出如何在 Spring Boot 中基于 ZooKeeper 实现服务注册/发现、分布式锁、配置中心以及集群协调的完整代码与最佳实践。所有示例均可直接复制运行。 1. ZooKeeper 架构与核心原理 1.1 角色 Leader&#xff1a;处理写请求&…

可验证随机函数-VRF

可验证随机函数&#xff08;Verifiable Random Function, VRF&#xff09;是一种结合密码学技术的伪随机数生成器&#xff0c;其核心特点是生成的随机数可被公开验证&#xff0c;且具有不可预测性和唯一性。以下是VRF的详细解析&#xff1a;1. 基本定义与核心特性 可验证性&…