vue3的生命周期
vue3的生命周期
主要分为四个阶段,创建、挂载、更新、销毁
创建阶段:setup
挂载阶段:onBeforeMount、onMounted
更新阶段:onBeforeUpdate、onUpdated
卸载阶段:onBeforeUnmount、onUnmounted
创建阶段
setup
Vue 3 中不再有 beforeCreate 和 created 钩子,因为在 Vue 3 的 Composition API 中,这些功能可以通过 setup() 函数来实现,该函数会在组件实例创建之前被调用。
setup() 是 Composition API 的核心,它是组件内所有 Composition API 钩子和逻辑的入口点。这个函数在组件实例创建之前被调用,但它不是生命周期的一部分。你可以在这个函数中定义响应式状态、方法等。
挂载阶段
onBeforeMount(挂载前)
这个钩子在组件挂载开始之前被调用,适合用于执行一些准备工作,比如数据预处理、设置初始状态等。
<template>
<div v-loading="loading">
<p>Name: {{ user?.name }}</p>
<p>Email: {{ user?.email }}</p>
<p>Price: {{ user?.price }}</p>
</div>
</template>
<script setup>
import { ref, onBeforeMount, onMounted } from "vue";
const user = ref(null);
const loading = ref(true);
// 模拟API请求
const fetchUserData = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "John Doe",
email: "john.doe@example.com",
price: 100,
});
}, 1000); // 模拟网络延迟
});
};
// 使用 onBeforeMount 钩子来获取数据
onBeforeMount(async () => {
console.log("Component is about to be mounted.");
try {
const Data = await fetchUserData();
// 数据预处理示例:价格转换为两位小数
Data.price = Data.price.toFixed(2);
user.value = Data;
} catch (error) {
console.error("Error fetching user data:", error);
} finally {
loading.value = false;
}
});
onMounted(() => {
console.log("onMounted");
});
</script>
onMounted(挂载完成)
这个钩子在组件挂载后立即调用,适合用来执行一些初始化操作,比如获取数据、设置事件监听器等。
<template>
<div v-loading="loading">
<p>Name: {{ user?.name }}</p>
<p>Email: {{ user?.email }}</p>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const user = ref(null);
const loading = ref(true);
// 模拟API请求
const fetchUserData = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "John Doe",
email: "john.doe@example.com",
});
}, 1000); // 模拟网络延迟
});
};
// 使用 onMounted 钩子来获取数据
onMounted(async () => {
console.log("Component has been mounted.");
try {
user.value = await fetchUserData();
} catch (error) {
console.error("Error fetching user data:", error);
} finally {
loading.value = false;
}
});
</script>
更新阶段
onBeforeUpdate(更新前)
这个钩子在组件因为数据变化而重新渲染之前被调用,适合用于执行一些操作,比如保存当前DOM状态、清理或重置某些变量等。
<template>
<div>
<h1>Todo List</h1>
<button @click="addItem">Add Item</button>
<ul ref="listContainer">
<li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, onBeforeUpdate, onMounted } from "vue";
const items = ref(["Item 1", "Item 2", "Item 3"]);
const listContainer = ref(null);
let scrollPosition = 0;
// 添加新项目到列表
const addItem = () => {
items.value.push(`Item ${items.value.length + 1}`);
};
// 在组件挂载时初始化滚动位置
onMounted(() => {
console.log("Component has been mounted.");
listContainer.value.scrollTop = scrollPosition;
});
// 在组件更新前保存滚动位置
onBeforeUpdate(() => {
console.log("Component is about to be updated.");
if (listContainer.value) {
scrollPosition = listContainer.value.scrollTop;
}
});
</script>
onUpdated(更新完成)
这个钩子在组件因为数据变化而重新渲染后被调用,适合用于执行一些操作,比如更新DOM、处理动画或触发某些依赖于最新DOM状态的操作。
<template>
<div>
<h1>Todo List</h1>
<button @click="addItem">Add Item</button>
<ul ref="listContainer" class="scrollable-list">
<li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, onBeforeUpdate, onUpdated, onMounted } from "vue";
const items = ref(["Item 1", "Item 2", "Item 3"]);
const listContainer = ref(null);
// 添加新项目到列表
function addItem() {
items.value.push(`Item ${items.value.length + 1}`);
}
// 在组件挂载时初始化滚动位置至底部
onMounted(() => {
console.log("onMounted");
scrollToBottom();
});
// 每次组件更新后将滚动位置设置为最底部
onUpdated(() => {
console.log("onUpdated");
scrollToBottom();
});
/**
* 将滚动条滚动至容器底部
*/
function scrollToBottom() {
if (listContainer.value) {
listContainer.value.scrollTop = listContainer.value.scrollHeight;
}
}
</script>
<style scoped>
.scrollable-list {
height: 150px; /* 设置固定高度以启用滚动 */
overflow-y: auto;
border: 1px solid #ccc;
padding: 10px;
margin-top: 10px;
}
li {
margin-bottom: 10px;
}
</style>
卸载阶段
onBeforeUnmount(卸载前)
这个钩子在组件实例被卸载之前调用,适合用于执行一些清理工作,比如移除事件监听器、取消定时器或清理订阅等。
<template>
<div>
<h1>Counter: {{ counter }}</h1>
<button @click="startCounter">Start</button>
<button @click="stopCounter">Stop</button>
<button @click="destroyComponent">Destroy Component</button>
</div>
</template>
<script setup>
import { ref, onBeforeUnmount } from "vue";
const counter = ref(0);
let timerId = null;
// 启动计时器
function startCounter() {
if (!timerId) {
timerId = setInterval(() => {
counter.value++;
console.log(`Counter updated: ${counter.value}`);
}, 1000);
}
}
// 停止计时器
function stopCounter() {
if (timerId) {
clearInterval(timerId);
timerId = null;
}
}
// 使用 onBeforeUnmount 钩子清理定时器
onBeforeUnmount(() => {
console.log("Component is about to be unmounted. Clearing timer.");
stopCounter();
});
// 模拟组件销毁
function destroyComponent() {
console.log("Destroying component...");
// 这里模拟销毁当前组件的行为
// 在实际应用中,你可能会通过路由导航或者条件渲染来实现组件的销毁
// 为了演示,这里直接调用 stopCounter 来清理资源
stopCounter();
}
</script>
<style scoped>
button {
margin-right: 10px;
}
</style>
onUnmounted(卸载完成)
<template>
<div>
<h1>Counter: {{ counter }}</h1>
<button @click="startCounter">Start</button>
<button @click="stopCounter">Stop</button>
<button @click="destroyComponent">Destroy Component</button>
</div>
</template>
<script setup>
import { ref, onBeforeUnmount, onUnmounted } from "vue";
const counter = ref(0);
let timerId = null;
// 启动计时器
function startCounter() {
if (!timerId) {
timerId = setInterval(() => {
counter.value++;
console.log(`Counter updated: ${counter.value}`);
}, 1000);
}
}
// 停止计时器
function stopCounter() {
if (timerId) {
clearInterval(timerId);
timerId = null;
}
}
// 使用 onBeforeUnmount 钩子清理定时器
onBeforeUnmount(() => {
console.log("Component is about to be unmounted. Clearing timer.");
stopCounter();
});
// 使用 onUnmounted 钩子确认定时器已被清除
onUnmounted(() => {
console.log("Component has been unmounted. Timer should be cleared.");
if (timerId === null) {
console.log("Timer successfully cleared.");
} else {
console.error("Timer was not cleared properly!");
}
});
// 模拟组件销毁
function destroyComponent() {
console.log("Destroying component...");
// 在实际应用中,你可能会通过路由导航或者条件渲染来实现组件的销毁
// 为了演示,这里直接调用 stopCounter 来清理资源
stopCounter();
}
</script>
<style scoped>
button {
margin-right: 10px;
}
</style>