MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Vue生命周期钩子 beforeCreate与created的使用场景

2021-07-215.8k 阅读

Vue 生命周期钩子概述

在深入探讨 beforeCreatecreated 钩子的使用场景之前,我们先来整体了解一下 Vue 的生命周期。Vue 实例从创建到销毁的过程,被称为生命周期。在这个过程中,Vue 会自动执行一系列的函数,也就是我们所说的生命周期钩子函数。这些钩子函数为开发者提供了在不同阶段操作 Vue 实例的能力,使得我们可以更加灵活地控制应用程序的行为。

Vue 的生命周期主要包括以下几个阶段:创建前(beforeCreate)、创建后(created)、挂载前(beforeMount)、挂载后(mounted)、更新前(beforeUpdate)、更新后(updated)、销毁前(beforeDestroy)和销毁后(destroyed)。每个阶段都有其特定的用途和意义,而 beforeCreatecreated 处于 Vue 实例创建的初期阶段。

beforeCreate 钩子

1. 本质与特点

beforeCreate 钩子是 Vue 实例生命周期中最早被调用的钩子函数。在这个阶段,Vue 实例的 datamethods 都还没有被初始化。也就是说,在 beforeCreate 中,我们无法访问到 data 中的数据,也不能调用 methods 中的方法。这是因为 Vue 实例此时还处于一个“初始化骨架”的状态,仅仅是创建了一个空的实例,尚未对数据和方法进行解析和绑定。

2. 使用场景

加载插件:在应用启动初期,我们可能需要加载一些全局的插件,比如日志记录插件、状态管理插件等。beforeCreate 钩子提供了一个合适的时机来进行这些操作。因为此时 Vue 实例还未完全初始化,不会受到 datamethods 中可能存在的逻辑干扰。

<!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 创建事件总线,可以确保它在整个应用生命周期的早期就可用,而且不会受到 datamethods 初始化的影响。

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 的对比与注意事项

  1. 访问数据和方法的差异beforeCreate 无法访问 datamethods,而 created 可以。这就决定了它们在使用场景上的不同,beforeCreate 更适合进行与 Vue 实例数据和方法无关的初始化操作,如加载插件、初始化第三方库等;而 created 则侧重于对数据的操作和依赖数据的逻辑处理。
  2. 执行时机的影响:由于 beforeCreate 执行得更早,在这个阶段进行的操作不会受到后续 datamethods 初始化的影响。而 created 钩子执行时,Vue 实例已经具备了完整的数据和方法,开发者可以基于这些进行复杂的业务逻辑编写。
  3. 性能方面的考虑:虽然在大多数情况下,beforeCreatecreated 钩子中的操作对性能影响不大,但如果在这些钩子中执行了大量复杂的计算或异步操作,可能会影响应用的启动性能。因此,在 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 生命周期钩子 beforeCreatecreated 的使用场景有了更深入的理解。在实际开发中,合理运用这两个钩子函数,可以让我们的 Vue 应用更加健壮、高效地运行。