Vue 3 生命周期与组合式 API 详解
生命周期钩子
在 Vue 3 中,生命周期钩子与 Vue 2 有所不同,特别是在组合式 API(***position API)中。以下是 Vue 3 中常用的生命周期钩子及其对应的功能:
-
setup:- 相当于 Vue 2 中的
beforeCreate和created。 - 在组件实例创建之前执行,适合进行数据初始化和事件监听。
- 相当于 Vue 2 中的
-
onBeforeMount:- 在组件挂载到 DOM 之前执行。
- 适合进行一些准备工作,如获取数据或设置初始状态。
-
onMounted:- 在组件挂载到 DOM 之后执行。
- 适合进行 DOM 操作或初始化第三方库。
-
onBeforeUpdate:- 在组件更新之前执行。
- 适合在数据更新前进行一些操作,如保存当前状态。
-
onUpdated:- 在组件更新之后执行。
- 适合在数据更新后进行一些操作,如更新 DOM 或触发其他逻辑。
-
onBeforeUnmount:- 在组件卸载之前执行。
- 适合进行一些清理工作,如取消事件监听或清除定时器。
-
onUnmounted:- 在组件卸载之后执行。
- 适合进行最后的清理工作,确保组件完全从 DOM 中移除。
ref 的使用
ref 是 Vue 3 中用于创建响应式引用的函数。它可以用于获取 DOM 元素、组件实例以及创建响应式变量。
-
获取 DOM 元素和组件:
- 使用
let 变量 = ref()创建一个引用。 - 在模板中使用
ref属性绑定到 DOM 元素或组件。 - 示例:
<template> <div ref="myDiv">This is a div</div> </template> <script> import { ref, onMounted } from 'vue'; export default { setup() { const myDiv = ref(null); onMounted(() => { console.log(myDiv.value); // 获取 DOM 元素 }); return { myDiv }; } }; </script>
- 使用
-
获取组件中的数据和方法:
- 使用
ref获取子组件实例,并通过defineExpose导出子组件的数据和方法。 - 示例:
<template> <Child***ponent ref="child" /> </template> <script> import { ref, onMounted } from 'vue'; import Child***ponent from './Child***ponent.vue'; export default { ***ponents: { Child***ponent }, setup() { const child = ref(null); onMounted(() => { console.log(child.value.someData); // 获取子组件的数据 child.value.someMethod(); // 调用子组件的方法 }); return { child }; } }; </script>
- 使用
defineExpose 进行导出
defineExpose 用于在组合式 API 中导出组件的数据和方法,供父组件通过 ref 访问。
- 示例:
import { defineExpose } from 'vue'; export default { setup() { const someData = ref('Hello'); function someMethod() { console.log('Method called'); } defineExpose({ someData, someMethod }); } };
Hook 函数
Hook 函数类似于 Vue 2 中的 mixin,用于封装可复用的功能代码。
- 示例:
import { ref } from 'vue'; export function useCounter() { const count = ref(0); function increment() { count.value++; } return { count, increment }; }
readonly 与 shallowReadonly
-
readonly:- 将对象的所有属性转换为只读响应式对象。
- 示例:
import { readonly } from 'vue'; const state = readonly({ count: 0 });
-
shallowReadonly:- 只会将根级属性设置为只读响应式对象,嵌套对象的属性仍然是可修改的。
- 示例:
import { shallowReadonly } from 'vue'; const state = shallowReadonly({ count: 0, nested: { value: 1 } });
shallowReactive 与 shallowRef
-
shallowReactive:- 只会对根属性进行响应式处理,而不会递归到对象的嵌套属性。
- 示例:
import { shallowReactive } from 'vue'; const state = shallowReactive({ count: 0, nested: { value: 1 } });
-
shallowRef:- 对该对象内部属性的修改不会被监听。
- 示例:
import { shallowRef } from 'vue'; const state = shallowRef({ count: 0 });
toRaw 与 markRaw
-
toRaw:- 用于获取代理对象的原始未代理版本。
- 示例:
import { reactive, toRaw } from 'vue'; const state = reactive({ count: 0 }); const rawState = toRaw(state);
-
markRaw:- 用于标记一个对象,使其永远不会被转换为响应式对象。
- 示例:
import { markRaw } from 'vue'; const rawObject = markRaw({ count: 0 });
toRef 与 toRefs
-
toRef:- 用于创建一个指定响应式对象的属性的可响应式引用。
- 示例:
import { reactive, toRef } from 'vue'; const state = reactive({ count: 0 }); const countRef = toRef(state, 'count');
-
toRefs:- 用于将一个响应式对象转换为一个包含多个属性的 ref 对象集合。
- 示例:
import { reactive, toRefs } from 'vue'; const state = reactive({ count: 0, message: 'Hello' }); const stateRefs = toRefs(state);
provide 与 inject
-
provide:- 用于在组件间传递数据。
- 示例:
import { provide } from 'vue'; provide('myKey', 'myValue');
-
inject:- 用于在组件中接收传递的数据。
- 示例:
import { inject } from 'vue'; const myValue = inject('myKey');
路由的跳转传参
-
声明式:
- 使用
router-link进行路由跳转。 - 示例:
<router-link :to="{ name: 'User', params: { id: 123 } }">User</router-link>
- 使用
-
函数式:
- 使用
useRouter进行路由跳转。 - 示例:
import { useRouter } from 'vue-router'; const router = useRouter(); function goToUser() { router.push({ name: 'User', params: { id: 123 } }); }
- 使用
-
接受参数:
- 使用
useRoute获取路由参数。 - 示例:
import { useRoute } from 'vue-router'; const route = useRoute(); console.log(route.params.id); // 获取路由参数
- 使用
总结
Vue 3 的组合式 API 提供了更灵活和强大的功能,帮助开发者更好地组织和复用代码。通过理解这些核心概念和 API,您可以更高效地开发 Vue 3 应用。