Skip to content

Mpx 生命周期

Mpx 作为跨端小程序框架,提供了一套统一的生命周期系统,抹平不同小程序平台生命周期的差异。本章节详细介绍 Mpx 中的各种生命周期钩子及其使用方法。

生命周期概述

Mpx 的生命周期体系包含以下几个层面:

  • 组件生命周期:组件实例的创建、挂载、更新、销毁过程
  • 页面生命周期:页面的加载、显示、隐藏、卸载过程
  • 应用生命周期:应用的启动、显示、隐藏、错误处理等
  • SSR 生命周期:服务端渲染特有的生命周期钩子

生命周期体系概览

Mpx 提供了两套生命周期使用方式:

  • 选项式 API:使用原生小程序生命周期或框架内置生命周期常量
  • 组合式 API:使用统一的 Vue 风格生命周期钩子

生命周期对应关系

框架内置生命周期选项式 API 用法组合式 API 钩子微信原生生命周期
BEFORECREATE页面: onLoad
组件:attached
- (可直接在 setup 中编写)页面: onLoad
组件:attached
CREATED页面: onLoad
组件:attached
- (可直接在 setup 中编写)页面: onLoad
组件:attached
BEFOREMOUNT页面:onReady
组件:ready
onBeforeMount页面:onReady
组件:ready
MOUNTED页面:onReady
组件:ready
onMounted页面:onReady
组件:ready
BEFOREUPDATE-onBeforeUpdate-
UPDATED-onUpdated-
BEFOREUNMOUNT页面:onUnload
组件:detached
onBeforeUnmount页面:onUnload
组件:detached
UNMOUNTED页面:onUnload
组件:detached
onUnmounted页面:onUnload
组件:detached
ONSHOWonShowonShowonShow
ONHIDEonHideonHideonHide
ONRESIZEonResizeonResizeonResize
SERVERPREFETCHserverPrefetchonServerPrefetch-

说明

  • 选项式 API 主要使用原生小程序生命周期(如 attachedreadydetached
  • 也可以使用框架内置生命周期常量(如 [CREATED]() {}[MOUNTED]() {} )来保持跨平台一致性
  • 组合式 API 提供了统一的 Vue 风格生命周期钩子

Options 语法(选项式 API)

选项式 API 支持两种生命周期写法:

  1. 原生小程序生命周期:直接使用各平台的原生生命周期名称
  2. 框架内置生命周期常量:使用统一的框架内置生命周期常量

组件生命周期

原生小程序生命周期:

  • created - 组件实例刚被创建时执行,此时不能调用 setData
  • attached - 组件实例进入页面节点树时执行
  • ready - 组件在视图层布局完成后执行
  • detached - 组件实例被从页面节点树移除时执行
  • pageLifetimes.show - 组件所在页面显示时执行
  • pageLifetimes.hide - 组件所在页面隐藏时执行

示例:

js
import { createComponent } from '@mpxjs/core'

createComponent({
  data: {
    message: 'Hello Mpx'
  },
  
  // 微信小程序原生组件生命周期
  created() {
    console.log('组件实例刚被创建')
    // 此时不能调用 setData,通常用于给组件 this 添加一些自定义属性字段
  },
  
  attached() {
    console.log('组件实例进入页面节点树时')
    // 可以访问 data,相当于 Vue 的 created + mounted
    console.log(this.data.message) // 'Hello Mpx'
  },
  
  ready() {
    console.log('组件在视图层布局完成后')
    // 可以访问 DOM 元素,类似 Vue 的 mounted
  },
  
  detached() {
    console.log('组件实例被从页面节点树移除时')
    // 清理定时器、事件监听器等,类似 Vue 的 beforeUnmount
  },
  pageLifetimes: {
    // 在组件中监听页面生命周期
    show() {
      console.log('组件所在页面被展示时')
    },
  
    hide() {
      console.log('组件所在页面被隐藏时')
    }
  }
})

组件生命周期常量:

  • BEFORECREATE - 实例初始化之后,数据观测初始化之前同步调用
  • CREATED - 实例创建完成,数据观测已完成
  • BEFOREMOUNT - 挂载开始之前被调用
  • MOUNTED - 实例被挂载后调用
  • BEFOREUPDATE - 数据更新时调用,发生在视图更新之前
  • UPDATED - 数据更新导致的重新渲染和更新完毕之后被调用
  • BEFOREUNMOUNT - 实例销毁之前调用
  • UNMOUNTED - 实例销毁后调用

示例:

js
import { createComponent, CREATED, MOUNTED, BEFOREUNMOUNT } from '@mpxjs/core'

createComponent({
  data: {
    timer: null
  },
  
  [CREATED]() {
    console.log('组件创建完成')
    // 初始化数据
  },
  
  [MOUNTED]() {
    console.log('组件挂载完成')
    // 启动定时器
    this.timer = setInterval(() => {
      console.log('定时任务执行')
    }, 1000)
  },
  
  [BEFOREUNMOUNT]() {
    console.log('组件即将销毁')
    // 清理定时器
    if (this.timer) {
      clearInterval(this.timer)
      this.timer = null
    }
  }
})

页面生命周期

  • onLoad - 页面加载时触发,只会调用一次
  • onReady - 页面初次渲染完成时触发,只会调用一次
  • onShow - 页面显示/切入前台时触发
  • onHide - 页面隐藏/切入后台时触发
  • onUnload - 页面卸载时触发
  • onResize - 监听页面尺寸变化

示例:

js
import { createPage, ONLOAD, ONSHOW, ONHIDE } from '@mpxjs/core'

createPage({
  data: {
    userInfo: null
  },
  
  // 使用原生页面生命周期
  onLoad(options) {
    console.log('页面加载', options)
    // 获取页面参数,初始化数据
  },
  
  onShow() {
    console.log('页面显示')
    // 页面显示时的逻辑
  },
  
  onHide() {
    console.log('页面隐藏')
    // 页面隐藏时的逻辑
  },
  
  onReady() {
    console.log('页面初次渲染完成')
    // 可以进行 DOM 操作
  },
  
  onUnload() {
    console.log('页面卸载')
    // 清理资源
  },
})

页面生命周期常量:

  • ONLOAD - 页面加载
  • ONSHOW - 页面显示
  • ONHIDE - 页面隐藏
  • ONRESIZE - 页面尺寸变化

示例:

js
import { createPage, ONLOAD, ONSHOW, ONHIDE, ONRESIZE } from '@mpxjs/core'

createPage({
  data: {
    userInfo: null
  },
  
  // 使用框架内置生命周期常量
  [ONLOAD](options) {
    console.log('使用内置常量 - 页面加载', options)
    // 获取页面参数,初始化数据
  },
  
  [ONSHOW]() {
    console.log('使用内置常量 - 页面显示')
    // 页面显示时的逻辑
  },
  
  [ONHIDE]() {
    console.log('使用内置常量 - 页面隐藏')
    // 页面隐藏时的逻辑
  },
  
  [ONRESIZE](res) {
    console.log('使用内置常量 - 页面尺寸变化', res)
    // 处理页面尺寸变化
  }
})

应用生命周期

应用生命周期用于 App 实例:

原生应用生命周期:

  • onLaunch - 应用初始化完成时触发,全局只触发一次
  • onShow - 应用启动,或从后台进入前台显示时触发
  • onHide - 应用从前台进入后台时触发
  • onError - 应用发生脚本错误或 API 调用报错时触发

示例:

js
import { createApp } from '@mpxjs/core'

createApp({
  // 应用生命周期
  onLaunch(options) {
    console.log('应用启动', options)
    // 应用初始化
  },
  
  onShow(options) {
    console.log('应用显示', options)
    // 应用从后台进入前台显示
  },
  
  onHide() {
    console.log('应用隐藏')
    // 应用从前台进入后台
  },
  
  onError(error) {
    console.log('应用错误', error)
    // 应用发生脚本错误或 API 调用报错时触发
  }
})

注意: 应用生命周期暂不支持框架内置生命周期常量,只能使用原生小程序应用生命周期。

Setup 语法(组合式 API)

组合式 API 使用统一的 Vue 风格生命周期钩子。

组件/页面通用生命周期

组件和页面都可用的生命周期钩子:

  • onBeforeMount - 挂载开始之前被调用
  • onMounted - 被挂载后调用
  • onBeforeUpdate - 数据更新时调用
  • onUpdated - 数据更新导致的重新渲染后调用
  • onBeforeUnmount - 在卸载实例之前调用
  • onUnmounted - 卸载实例后调用
  • onShow - 页面显示/切入前台时触发
  • onHide - 页面隐藏/切入后台时触发
  • onResize - 页面尺寸变化时触发

注意setup 函数本身相当于 beforeCreate + created,可以直接在其中编写初始化逻辑。

示例:

js
import { 
  createComponent, 
  onBeforeMount,
  onMounted, 
  onBeforeUpdate,
  onUpdated, 
  onBeforeUnmount,
  onUnmounted,
  onShow,
  onHide,
  onResize
} from '@mpxjs/core'

createComponent({
  setup() {
    console.log('setup 执行 - 相当于 beforeCreate + created')
    
    // 组件挂载前
    onBeforeMount(() => {
      console.log('组件即将挂载')
    })
    
    // 组件挂载后
    onMounted(() => {
      console.log('组件已挂载')
      // 可以访问 DOM 元素和 refs
    })
    
    // 数据更新前
    onBeforeUpdate(() => {
      console.log('数据即将更新')
    })
    
    // 数据更新后
    onUpdated(() => {
      console.log('数据更新完成')
      // 注意:onUpdated 不保证所有子组件都重新渲染完毕
      // 如果需要等待整个视图渲染完毕,使用 nextTick
    })
    
    // 组件卸载前
    onBeforeUnmount(() => {
      console.log('组件即将卸载')
      // 清理定时器、事件监听器等
    })
    
    // 组件卸载后
    onUnmounted(() => {
      console.log('组件已卸载')
    })
    
    // 页面相关生命周期(组件中监听页面的生命周期)
    onShow(() => {
      console.log('页面显示时,组件需要处理的逻辑')
    })
    
    onHide(() => {
      console.log('页面隐藏时,组件需要处理的逻辑')
    })
    
    onResize((res) => {
      console.log('页面尺寸变化时,组件需要处理的逻辑', res)
    })
    
    return {
      // 暴露给模板的数据和方法
    }
  }
})

页面特有生命周期

仅页面可用的生命周期钩子:

  • onLoad - 页面加载时触发,接收页面参数

示例:

js
import { 
  createPage,
  onLoad,
  // 其他通用生命周期钩子请参考上面的"组件页面通用生命周期"部分
} from '@mpxjs/core'

createPage({
  setup() {
    // 页面特有生命周期
    onLoad((options) => {
      console.log('页面加载', options)
      // 处理页面参数
    })
    
    return {}
  }
})

应用生命周期

注意: 应用实例暂不支持 setup 语法,只能使用选项式 API。

SSR 生命周期

Mpx 2.9+ 版本提供了专门的 web SSR(服务端渲染)生命周期钩子:

通用生命周期

serverPrefetch / SERVERPREFETCH

可在应用/页面/组件中使用,仅在服务端执行

用于服务端数据预取,支持两种定义方式:

选项式 API:

js
import { createPage, SERVERPREFETCH } from '@mpxjs/core'
import useStore from '../store/index'

createPage({
  data: {
    articleList: []
  },
  
  // 方式1:使用方法名
  serverPrefetch() {
    const store = useStore(this.$pinia)
    return store.fetchArticleList(this.$route.query.category)
      .then(data => {
        this.articleList = data
      })
  },
  
  // 方式2:使用内置生命周期常量(等价于上面)
  // [SERVERPREFETCH]() {
  //   // 与 serverPrefetch 完全等价
  // }
})

组合式 API:

js
import { createPage, onServerPrefetch, ref } from '@mpxjs/core'
import useStore from '../store/index'

createPage({
  setup() {
    const articleList = ref([])
    const store = useStore()
    
    onServerPrefetch(() => {
      return store.fetchArticleList()
        .then(data => {
          articleList.value = data
        })
    })
    
    return { articleList }
  }
})

应用生命周期

应用级别的 SSR 生命周期钩子:

  • onAppInit - 应用初始化(服务端和客户端都执行)
  • onSSRAppCreated - 应用创建完成(仅服务端执行)
js
// app.mpx
import { createApp } from '@mpxjs/core'
import { createPinia } from '@mpxjs/pinia'

createApp({
  // 应用初始化,创建全局状态管理实例
  onAppInit() {
    const pinia = createPinia()
    return { pinia }
  },
  
  // 应用创建完成,进行路由匹配和状态同步
  onSSRAppCreated({ app, router, pinia, context }) {
    return router.push(context.url).then(() => {
      context.state = { pinia: pinia.state.value }
      return app
    })
  }
})

最佳实践

1. 选择合适的生命周期

选项式 API(原生小程序生命周期)

js
// ✅ 正确:在 attached 中初始化数据
attached() {
  this.fetchUserInfo()
}

// ✅ 正确:在 ready 中操作 DOM
ready() {
  // 操作组件节点
  this.createSelectorQuery().select('.chart').boundingClientRect().exec()
}

// ✅ 正确:在 detached 中清理资源
detached() {
  clearInterval(this.timer)
  // 移除事件监听,定时器等
}

组合式 API(Vue 风格生命周期)

js
// ✅ 正确:在 setup 中初始化数据,onMounted 中操作 DOM
setup() {
  // 数据初始化可以直接在 setup 中进行
  const userInfo = ref(null)
  
  onMounted(() => {
    // DOM 操作
  })
  
  onBeforeUnmount(() => {
    // 清理资源
    clearInterval(timer)
  })
}