Vue生命周期钩子 beforeCreate与created的使用场景
Vue 生命周期钩子概述
在深入探讨 beforeCreate
与 created
钩子的使用场景之前,我们先来整体了解一下 Vue 的生命周期。Vue 实例从创建到销毁的过程,被称为生命周期。在这个过程中,Vue 会自动执行一系列的函数,也就是我们所说的生命周期钩子函数。这些钩子函数为开发者提供了在不同阶段操作 Vue 实例的能力,使得我们可以更加灵活地控制应用程序的行为。
Vue 的生命周期主要包括以下几个阶段:创建前(beforeCreate
)、创建后(created
)、挂载前(beforeMount
)、挂载后(mounted
)、更新前(beforeUpdate
)、更新后(updated
)、销毁前(beforeDestroy
)和销毁后(destroyed
)。每个阶段都有其特定的用途和意义,而 beforeCreate
和 created
处于 Vue 实例创建的初期阶段。
beforeCreate 钩子
1. 本质与特点
beforeCreate
钩子是 Vue 实例生命周期中最早被调用的钩子函数。在这个阶段,Vue 实例的 data
和 methods
都还没有被初始化。也就是说,在 beforeCreate
中,我们无法访问到 data
中的数据,也不能调用 methods
中的方法。这是因为 Vue 实例此时还处于一个“初始化骨架”的状态,仅仅是创建了一个空的实例,尚未对数据和方法进行解析和绑定。
2. 使用场景
加载插件:在应用启动初期,我们可能需要加载一些全局的插件,比如日志记录插件、状态管理插件等。beforeCreate
钩子提供了一个合适的时机来进行这些操作。因为此时 Vue 实例还未完全初始化,不会受到 data
或 methods
中可能存在的逻辑干扰。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>beforeCreate 加载插件示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script>
// 模拟一个简单的日志插件
const logPlugin = {
install(Vue) {
Vue.prototype.$log = function(message) {
console.log('日志记录:', message);
};
}
};
new Vue({
el: '#app',
beforeCreate() {
this.$options.plugins.push(logPlugin);
this.$log('应用启动中...');
},
data() {
return {
message: 'Hello, Vue!'
};
},
methods: {
showMessage() {
this.$log(this.message);
}
}
});
</script>
</body>
</html>
在上述代码中,我们在 beforeCreate
钩子中注册了一个简单的日志插件 logPlugin
,并使用 $log
方法记录应用启动的信息。虽然在 beforeCreate
中无法访问 data
中的 message
数据,但我们可以利用这个时机完成插件的加载和初始化操作。
初始化非 Vue 相关的第三方库:有些第三方库与 Vue 的耦合度较低,它们的初始化不需要依赖 Vue 实例的特定数据或方法。在这种情况下,beforeCreate
是一个理想的初始化时机。例如,初始化一个图表库,我们可能只需要在应用启动时配置一些全局的图表设置,而不需要等待 Vue 实例完全初始化。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>beforeCreate 初始化第三方库示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div id="app"></div>
<script>
new Vue({
el: '#app',
beforeCreate() {
// 初始化 Chart.js 的全局配置
Chart.defaults.global.defaultFontColor = 'blue';
},
data() {
return {
chartData: {
labels: ['January', 'February', 'March'],
datasets: [{
label: 'My First Dataset',
data: [65, 59, 80],
fill: false,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
}
};
},
mounted() {
new Chart(this.$el, {
type: 'line',
data: this.chartData
});
}
});
</script>
</body>
</html>
在这个例子中,我们在 beforeCreate
钩子中对 Chart.js 进行了全局配置。这样,当后续在 mounted
钩子中创建具体的图表实例时,就会应用这些配置。
配置全局事件总线:全局事件总线(Event Bus)是一种在 Vue 应用中实现组件间通信的常用方式。在应用启动初期,我们可以在 beforeCreate
钩子中创建并配置全局事件总线。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>beforeCreate 配置全局事件总线示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child-component></child-component>
</div>
<script>
Vue.component('child-component', {
template: `<button @click="sendEvent">发送事件</button>`,
methods: {
sendEvent() {
this.$root.$emit('custom-event', '事件来自子组件');
}
}
});
new Vue({
el: '#app',
beforeCreate() {
// 创建全局事件总线
this.$bus = new Vue();
},
created() {
this.$bus.$on('custom-event', (message) => {
console.log('接收到的事件消息:', message);
});
}
});
</script>
</body>
</html>
在上述代码中,我们在 beforeCreate
钩子中创建了一个全局事件总线 $bus
。然后在 created
钩子中监听子组件通过 $bus
发送的自定义事件。这里在 beforeCreate
创建事件总线,可以确保它在整个应用生命周期的早期就可用,而且不会受到 data
或 methods
初始化的影响。
created 钩子
1. 本质与特点
created
钩子在 beforeCreate
之后被调用。在这个阶段,Vue 实例已经完成了数据观测(data observer)、属性和方法的初始化。这意味着我们可以访问 data
中的数据,也能够调用 methods
中的方法。created
钩子就像是 Vue 实例已经搭建好了基本框架,并且把数据和方法都准备好了,开发者可以在这个阶段开始对数据进行操作,执行与数据相关的逻辑。
2. 使用场景
数据请求:在很多应用中,我们需要从服务器获取数据来填充页面。created
钩子是发起数据请求的常用位置。因为此时 Vue 实例已经初始化了数据,我们可以将获取到的数据直接赋值给 data
中的属性,以便在模板中进行渲染。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>created 数据请求示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in items" :key="item.id">{{ item.title }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
items: []
};
},
created() {
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
this.items = response.data;
})
.catch(error => {
console.error('数据请求错误:', error);
});
}
});
</script>
</body>
</html>
在上述代码中,我们在 created
钩子中使用 Axios 发起了一个 GET 请求,从 JSONPlaceholder API 获取文章列表数据,并将其赋值给 data
中的 items
属性。这样,模板中的 <li>
元素就能根据获取到的数据进行渲染。
数据预处理:在数据展示或进一步操作之前,可能需要对数据进行一些预处理。比如,将日期格式进行转换、对文本进行格式化等。由于 created
钩子可以访问到 data
中的数据,所以是进行数据预处理的合适时机。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>created 数据预处理示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in processedItems" :key="item.id">{{ item.formattedTitle }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
rawItems: [
{ id: 1, title: 'vue basic' },
{ id: 2, title: 'javascript advanced' }
],
processedItems: []
};
},
created() {
this.processedItems = this.rawItems.map(item => {
return {
id: item.id,
formattedTitle: item.title.charAt(0).toUpperCase() + item.title.slice(1)
};
});
}
});
</script>
</body>
</html>
在这个例子中,我们在 created
钩子中对 rawItems
中的数据进行了预处理,将每个标题的首字母大写,然后将处理后的数据存储在 processedItems
中,供模板渲染使用。
初始化组件间通信相关的数据:如果组件之间需要共享数据或进行通信,created
钩子可以用来初始化相关的数据。例如,父组件向子组件传递数据,或者多个兄弟组件之间通过事件总线进行通信,在 created
阶段可以设置好初始状态。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>created 初始化组件间通信数据示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child-component :sharedData="sharedData"></child-component>
</div>
<script>
Vue.component('child-component', {
props: ['sharedData'],
template: `<div>共享数据: {{ sharedData }}</div>`
});
new Vue({
el: '#app',
data() {
return {
sharedData: ''
};
},
created() {
this.sharedData = '这是父组件共享给子组件的数据';
}
});
</script>
</body>
</html>
在上述代码中,父组件在 created
钩子中初始化了要共享给子组件的数据 sharedData
。这样,子组件在渲染时就能接收到并展示这个数据。
绑定自定义事件:在 created
钩子中,我们可以为 Vue 实例绑定自定义事件。这些自定义事件可以在后续的逻辑中触发,用于实现特定的业务逻辑。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>created 绑定自定义事件示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="triggerCustomEvent">触发自定义事件</button>
</div>
<script>
new Vue({
el: '#app',
created() {
this.$on('custom-event', () => {
console.log('自定义事件被触发');
});
},
methods: {
triggerCustomEvent() {
this.$emit('custom-event');
}
}
});
</script>
</body>
</html>
在这个例子中,我们在 created
钩子中为 Vue 实例绑定了一个自定义事件 custom - event
,并在 methods
中的 triggerCustomEvent
方法中触发这个事件。当用户点击按钮时,就会在控制台输出“自定义事件被触发”。
beforeCreate 与 created 的对比与注意事项
- 访问数据和方法的差异:
beforeCreate
无法访问data
和methods
,而created
可以。这就决定了它们在使用场景上的不同,beforeCreate
更适合进行与 Vue 实例数据和方法无关的初始化操作,如加载插件、初始化第三方库等;而created
则侧重于对数据的操作和依赖数据的逻辑处理。 - 执行时机的影响:由于
beforeCreate
执行得更早,在这个阶段进行的操作不会受到后续data
和methods
初始化的影响。而created
钩子执行时,Vue 实例已经具备了完整的数据和方法,开发者可以基于这些进行复杂的业务逻辑编写。 - 性能方面的考虑:虽然在大多数情况下,
beforeCreate
和created
钩子中的操作对性能影响不大,但如果在这些钩子中执行了大量复杂的计算或异步操作,可能会影响应用的启动性能。因此,在beforeCreate
中加载插件或初始化第三方库时,要确保这些操作是轻量级的;在created
中进行数据请求或数据处理时,要合理控制请求的频率和数据处理的复杂度。
结合实际项目的案例分析
1. 单页应用(SPA)的数据加载与初始化
假设我们正在开发一个单页应用,其中有一个用户信息展示页面。在这个页面中,需要从服务器获取用户的基本信息、订单记录等数据来进行展示。同时,我们还使用了一些第三方的 UI 组件库和状态管理库。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SPA 数据加载与初始化示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex/dist/vuex.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
<div id="app">
<h1>用户信息</h1>
<p>姓名: {{ user.name }}</p>
<p>邮箱: {{ user.email }}</p>
<h2>订单记录</h2>
<ul>
<li v-for="order in orders" :key="order.id">{{ order.product }}</li>
</ul>
</div>
<script>
// 状态管理仓库
const store = new Vuex.Store({
state: {
user: null,
orders: []
},
mutations: {
setUser(state, user) {
state.user = user;
},
setOrders(state, orders) {
state.orders = orders;
}
}
});
new Vue({
el: '#app',
store,
beforeCreate() {
// 加载 Bootstrap UI 组件库相关的初始化操作(假设需要一些初始化配置)
// 这里可以添加一些全局样式设置等
document.body.classList.add('container');
// 注册 Vuex 插件(假设我们有自定义的 Vuex 插件)
const customVuexPlugin = store => {
console.log('自定义 Vuex 插件已加载');
};
this.$options.store.$subscribe(customVuexPlugin);
},
created() {
// 获取用户信息
axios.get('https://api.example.com/user')
.then(response => {
this.$store.commit('setUser', response.data);
})
.catch(error => {
console.error('获取用户信息错误:', error);
});
// 获取订单记录
axios.get('https://api.example.com/orders')
.then(response => {
this.$store.commit('setOrders', response.data);
})
.catch(error => {
console.error('获取订单记录错误:', error);
});
},
data() {
return {
// 这里可以定义一些局部数据
};
}
});
</script>
</body>
</html>
在这个例子中,我们在 beforeCreate
钩子中进行了 UI 组件库的初始化配置(通过添加全局样式类)以及 Vuex 插件的注册。而在 created
钩子中,发起了两个数据请求,分别获取用户信息和订单记录,并将数据提交到 Vuex 的状态管理仓库中。这样,页面就能根据获取到的数据进行渲染。
2. 多页面应用(MPA)中的公共逻辑处理
在一个多页面应用中,有多个页面需要使用相同的全局配置和公共数据。例如,每个页面都需要记录用户的登录状态,并且在页面加载时进行一些公共的初始化操作。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MPA 公共逻辑处理示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<p v-if="isLoggedIn">用户已登录</p>
<p v-else>用户未登录</p>
</div>
<script>
new Vue({
el: '#app',
beforeCreate() {
// 初始化全局配置,例如设置 API 基础 URL
this.$http = axios.create({
baseURL: 'https://api.example.com'
});
// 假设这里有一个全局的用户登录状态管理函数
const checkLoginStatus = () => {
// 这里可以通过 cookie 或 localStorage 等方式检查登录状态
return true; // 模拟已登录状态
};
this.$options.checkLoginStatus = checkLoginStatus;
},
created() {
this.isLoggedIn = this.$options.checkLoginStatus();
// 可以在这里进行一些基于登录状态的其他初始化操作
if (this.isLoggedIn) {
this.$http.get('/user/profile')
.then(response => {
console.log('获取用户个人资料:', response.data);
})
.catch(error => {
console.error('获取用户个人资料错误:', error);
});
}
},
data() {
return {
isLoggedIn: false
};
}
});
</script>
</body>
</html>
在这个例子中,我们在 beforeCreate
钩子中初始化了全局的 HTTP 请求实例 $http
,并定义了一个检查用户登录状态的全局函数 checkLoginStatus
。然后在 created
钩子中,调用这个函数来确定用户的登录状态,并根据登录状态进行后续的操作,如获取用户个人资料。
通过以上详细的介绍、代码示例以及案例分析,相信大家对 Vue 生命周期钩子 beforeCreate
与 created
的使用场景有了更深入的理解。在实际开发中,合理运用这两个钩子函数,可以让我们的 Vue 应用更加健壮、高效地运行。