【Vue调用方法】 created和mounted 调用时机对比(大全)

发布于:2025-06-24 ⋅ 阅读:(18) ⋅ 点赞:(0)

前言

开发中遇到的问题:在一个使用了多个图表的页面中,数据量很大,并且接口还要定时获取,将 获取图表数据的方法写在mounted()里面了,页面在使用时,发现 容易出现卡顿问题,于是,进行了代码排查及优化。

其中,我优化的一个点:就是将获取图表及列表数据的方法 放在created里面去调用了。

现在,我来解释一下为什么在这种场景下,将接口请求放在 created 中是更优的选择,以及为什么它不会对页面渲染产生负面影响。

1. 为什么从 mounted 移到 created?—— 为了“更快”

  • 并行工作:当我们将 API 请求放在 created 钩子中时,组件实例一被创建,数据请求的指令就立刻发出去了。然后,Vue 会继续执行接下来的生命周期,包括模板编译和 DOM 挂载。
  • 节省等待时间:在这个过程中,数据请求(这是一个网络I/O操作,比较耗时)和 DOM 渲染(这是一个CPU操作)是并行进行的。等到 mounted 钩子执行,DOM 渲染完成时,我们的数据很可能已经从服务器返回了。这样,用户就能更快地看到最终呈现了数据的页面。
  • 反之:如果放在 mounted 里,必须等 DOM 完全渲染好之后,才开始发送数据请求。这就意味着 “渲染” 和 “数据请求” 是串行进行的,用户会先看到一个空的骨架页面,然后再等待数据返回并填充,总体的“白屏”或“空内容”时间会更长。

2. 会对页面渲染有影响吗?—— 不会,因为是异步的

这是最关键的一点。

  • API 请求是异步的:当你调用 this.getList() 时,它内部的 getHumiture(param) 会返回一个 PromiseJavaScript 不会傻傻地“卡住”并等待网络请求返回。它会立即继续执行后续代码,也就是完成 created 钩子,然后进入 mounted 钩子去渲染 DOM。
  • Vue 的响应式系统:
  1. 初始渲染时,DOM 会根据 data 中的初始值(例如一个空数组 [])进行渲染。所以用户会先看到一个空的表格或图表。
  1. 几百毫秒或几秒后,当 getHumiture 的 Promise 完成,.then() 里的回调函数被执行。
  1. 在这个回调函数里,你执行了 this.humitureData = res.data 这样的操作。
  1. Vue 的响应式系统会侦测到 humitureData 这个数据的变化,并自动地、高效地去更新 DOM 中依赖了这个数据的部分。

前言总结 

created mounted
执行时机 实例已创建,DOM 未渲染 实例已挂载,DOM 已渲染
能否访问DOM ❌ 不能 (e.g., this.$refs 是 undefined) ✅ 可以
适合做的事 初始化数据(API请求)、开启定时器、事件监听 操作DOM、集成需要DOM的第三方库 (e.g., ECharts 初始化)
性能表现 更优,数据请求与DOM渲染并行 稍慢,数据请求在DOM渲染后才开始

一、核心区别与对比

created | mounted 

特性

created 

mounted 

执行时机

Vue 实例已创建,但 DOM 尚未生成

 Vue 实例已挂载到页面上,DOM 已生成 

数据访问

✅ 可以访问 data、props、computed、methods

✅ 可以访问 data、props、computed、methods 

DOM 访问

❌ 不能this.$el 不存在,this.$refs 为空对象 

 ✅ 可以。能安全地访问和操作所有 DOM 元素 

服务器端渲染(SSR)

✅ 会执行

❌ 不会执行

核心用途

初始化数据状态,进行与 DOM 无关的异步操作 

执行依赖 DOM 的操作 

二、使用场景分析:“应该放在哪里?”

你可以根据这个简单的逻辑来判断:“我的这个操作,需要用到页面上的真实 DOM 元素吗?”

场景 1:应该放在 created 的情况(通用 & 推荐)

核心原则:所有与 DOM 无关的初始化操作,都应该优先放在 created

  • 1. 发起 API 请求获取数据(最常见)

  • 为什么? 这能让数据请求与 DOM 渲染并行,用户能更快看到最终内容。这是提升首屏加载性能的关键一步。
    created() {
           // 获取用户列表,完全不需要 DOM
           this.fetchUserList(); 
    }  
  • 2. 初始化非响应式的数据或状态

  • 为什么? 此时实例已经创建,可以安全地挂载一些属性。
    created() {
      this.myTimer = null; // 初始化一个定时器变量
      this.eventBusListener = () => { /* ... */ }; // 定义一个事件监听器
     }
  • 3. 开启定时器 (setInterval) 或事件总线监听 (eventBus.$on)

  • 为什么? 这些操作同样不依赖 DOM,越早启动越好。(注意:一定要在 beforeDestroy 中销毁它们!
  • 示例:
created() {
  this.myTimer = setInterval(this.fetchUpdates, 5000);
}
beforeDestroy() {
  clearInterval(this.myTimer);
}

 场景 2:必须放在 mounted 的情况(特殊 & 依赖 DOM)

核心原则:任何需要读取或修改页面上真实 DOM 元素的操作,必须放在 mounted

  • 1. 初始化需要 DOM 的第三方库(最常见)

  • 为什么? 像 ECharts、D3.js、CodeMirror 等库,初始化时都需要一个已经存在的 DOM 容器作为挂载点。
  • 示例:
    mounted() {
       // ECharts 需要一个 div 容器,这个 div 必须在 mounted 后才存在
       const myChart = echarts.init(this.$refs.mainChart); 
       myChart.setOption(/* ... */);
    }
  • 2. 直接操作 DOM

  • 为什么? 这是 mounted 的本职工作。比如获取某个元素的尺寸、位置,或者手动添加/移除 class。
  • 示例:
    mounted() {
      const componentWidth = this.$el.clientWidth; // 获取组件根元素的宽度
      const specificDiv = document.getElementById('my-div'); // 使用原生 API
    }
  • 3. 需要访问子组件的 DOM 或方法

  • 为什么? 通过 this.$refs 访问子组件实例,并调用其方法或访问其 DOM,必须确保子组件也已经被挂载。
  • 示例:
  •  mounted() {
       // 调用子组件暴露的方法
       this.$refs.myChildComponent.focusInput(); 
    }

    三、总结与最佳实践

  • 养成习惯:默认将所有数据请求 (axios, fetch) 都放在 created 里。这几乎总是一个更好的选择。
  • 明确界限:只有当你写下 this.$refs、this.$el、document.getElementById,或者需要初始化一个图表/编辑器这类需要“画布”的库时,才把代码放进 mounted
  • 注意 this.$nextTick:有时在 created 或 methods 中修改数据后,你想立即访问更新后的 DOM,此时 mounted 帮不了你,你需要使用 this.$nextTick
    this.list.push('newItem');
    this.$nextTick(() => {
      // 在这里可以访问到渲染了 'newItem' 后的 DOM
      const lastItem = this.$refs.list.lastChild; 
    });


网站公告

今日签到

点亮在社区的每一天
去签到