创建阶段

创建阶段是 Vue 实例生命周期的第一个阶段。在这个阶段,Vue 完成实例的初始化工作,包括数据观测、事件配置等。

创建阶段包含两个钩子:beforeCreate 和 created。

beforeCreate 钩子

beforeCreate 在实例初始化之后,数据观测和事件配置之前调用。

执行时机

new Vue()
    │
    ▼
beforeCreate  ← 此时 data、methods 都不可用
    │
    ▼
初始化 data、methods、computed、watch
    │
    ▼
created

特点

  • 实例已创建,但未完成初始化
  • 无法访问 data、methods、computed
  • 无法访问 this.$el
  • 适合做一些不需要实例数据的初始化工作

示例

new Vue({
  data: {
    message: 'Hello'
  },
  methods: {
    greet() {
      console.log(this.message)
    }
  },
  beforeCreate() {
    console.log('beforeCreate')
    console.log(this.message)
    console.log(this.greet)
    console.log(this.$el)
  }
})

输出结果:

beforeCreate
undefined
undefined
undefined

使用场景

beforeCreate 的使用场景较少,常见的有:

1. 加载动画开始

beforeCreate() {
  NProgress.start()
}

2. 插件初始化

某些插件需要在 Vue 初始化之前设置:

beforeCreate() {
  this.$options.plugins = loadPlugins()
}

created 钩子

created 在实例创建完成后调用。此时实例已完成数据观测、属性和方法的运算、watch/event 事件回调。

执行时机

beforeCreate
    │
    ▼
初始化 data、methods、computed、watch
    │
    ▼
created  ← 此时 data、methods 都可访问

特点

  • 可以访问 data、methods、computed
  • 可以调用 methods 中的方法
  • 无法访问 this.$el(DOM 未渲染)
  • 适合数据初始化、异步请求

示例

new Vue({
  data: {
    message: 'Hello',
    users: []
  },
  methods: {
    greet() {
      console.log(this.message)
    }
  },
  created() {
    console.log('created')
    console.log(this.message)
    this.greet()
    this.fetchUsers()
  },
  methods: {
    async fetchUsers() {
      const response = await fetch('/api/users')
      this.users = await response.json()
    }
  }
})

输出结果:

created
Hello
Hello

使用场景

created 是最常用的生命周期钩子之一:

1. 发起异步请求

created() {
  this.loadUserInfo()
  this.loadSettings()
},
methods: {
  async loadUserInfo() {
    const res = await api.getUserInfo()
    this.userInfo = res.data
  },
  async loadSettings() {
    const res = await api.getSettings()
    this.settings = res.data
  }
}

2. 初始化数据

created() {
  this.initForm()
},
methods: {
  initForm() {
    this.form = {
      username: '',
      email: '',
      role: 'user'
    }
  }
}

3. 设置定时器

created() {
  this.timer = setInterval(() => {
    this.updateTime()
  }, 1000)
},
beforeDestroy() {
  clearInterval(this.timer)
}

4. 事件监听

created() {
  eventBus.$on('user-login', this.handleLogin)
  eventBus.$on('user-logout', this.handleLogout)
},
beforeDestroy() {
  eventBus.$off('user-login', this.handleLogin)
  eventBus.$off('user-logout', this.handleLogout)
}

beforeCreate vs created

两个钩子的对比:

特性beforeCreatecreated
data不可访问可访问
methods不可访问可访问
computed不可访问可访问
watch不可访问可访问
$el不可访问不可访问
使用频率

实际案例

用户信息组件

Vue.component('user-profile', {
  template: `
    <div class="user-profile">
      <div v-if="loading">加载中...</div>
      <div v-else>
        <h2>{{ user.name }}</h2>
        <p>{{ user.email }}</p>
      </div>
    </div>
  `,
  data() {
    return {
      user: null,
      loading: true
    }
  },
  created() {
    this.loadUser()
  },
  methods: {
    async loadUser() {
      try {
        const response = await fetch(`/api/users/${this.userId}`)
        this.user = await response.json()
      } catch (error) {
        console.error('加载用户失败:', error)
      } finally {
        this.loading = false
      }
    }
  },
  props: {
    userId: {
      type: Number,
      required: true
    }
  }
})

表单初始化

Vue.component('user-form', {
  template: `
    <form @submit.prevent="submit">
      <input v-model="form.name" placeholder="姓名">
      <input v-model="form.email" placeholder="邮箱">
      <button type="submit">提交</button>
    </form>
  `,
  props: {
    initialData: Object
  },
  data() {
    return {
      form: {
        name: '',
        email: ''
      }
    }
  },
  created() {
    if (this.initialData) {
      this.form = { ...this.initialData }
    }
  },
  methods: {
    submit() {
      this.$emit('submit', this.form)
    }
  }
})

数据验证

new Vue({
  data() {
    return {
      config: null,
      error: null
    }
  },
  created() {
    this.validateConfig()
  },
  methods: {
    validateConfig() {
      const config = localStorage.getItem('app-config')
      
      if (!config) {
        this.error = '配置不存在'
        return
      }
      
      try {
        this.config = JSON.parse(config)
        
        if (!this.config.apiKey) {
          this.error = 'API Key 缺失'
        }
      } catch (e) {
        this.error = '配置格式错误'
      }
    }
  }
})

服务端渲染注意

在服务端渲染(SSR)时,created 钩子会在服务端执行:

export default {
  data() {
    return {
      article: null
    }
  },
  created() {
    if (typeof window === 'undefined') {
      console.log('服务端执行')
    } else {
      console.log('客户端执行')
    }
  }
}

注意:

  • created 在 SSR 时会执行
  • mounted 只在客户端执行
  • 避免在 created 中使用 window、document 等浏览器 API

最佳实践

1. 数据请求放在 created

created() {
  this.fetchData()
}

2. 避免在 created 中操作 DOM

created() {
  console.log(this.$el)
}

3. 合理使用异步操作

created() {
  Promise.all([
    this.fetchUser(),
    this.fetchSettings()
  ]).then(() => {
    this.ready = true
  })
}