Skip to content

定义页面

警告

definePage 已不被推荐使用,请使用 defineComponent 定义页面,详见定义页面组件

原因是 definePagesetup 会在所有子组件的 setup 之后执行,所以你不能在 definePage 中使用 provide,而且子组件 setup 执行时,其 props 可能也未初始化。

小程序中的每个页面都可以在对应的 js 文件中使用 definePage 函数进行定义。它是 Page 函数的超集,它额外接收一个 setup 函数。

page.js
js
import { definePage, ref, computed } from '@vue-mini/core'

definePage({
  setup() {
    const count = ref(0)
    const double = computed(() => count.value * 2)

    const increment = () => {
      state.count++
    }

    return { count, double, increment }
  },
})

如果 setup 返回一个对象,则对象的属性将会被合并到页面实例上,可以直接在页面模版中使用。

page.wxml
xml
<button bind:tap="increment">
  {{ count }} X 2 = {{ double }}
</button>

注意 setup 返回的 ref 在模板中会自动解开,不需要写 .value

setup

注意

setup 只能是同步函数。

  • 调用时机

setup 会在 onLoad 阶段被调用。返回的数据和方法也会在此时才会被合并到页面实例上,所以模版初次渲染时数据可能是 undefined。不过小程序模版对此做了兼容,所以不用担心会报错。

  • 调用顺序

由于页面 onLoad 钩子会晚于所有子组件的 attached 钩子执行,所以 definePagesetup 函数会晚于所有子组件的 setup 函数执行。这在某些情况下(如:依赖注入)可能会造成问题,如果你需要 setup 函数按组件树从上到下依次执行,可以使用页面组件

  • 参数

setup 函数的第一个参数与 onLoad 的参数相同。

page.js
js
import { definePage } from '@vue-mini/core'

definePage({
  setup(query) {
    // query 为打开当前页面路径中的参数
  },
})

第二个参数提供了一个上下文对象,从小程序页面 this 中选择性的暴露了一些属性。

page.js
js
import { definePage } from '@vue-mini/core'

definePage({
  setup(query, context) {
    context.is
    context.route
    context.exitState
    context.getOpenerEventChannel
    // ...
  },
})
  • this 的用法

thissetup() 中不可用。这是为了避免混乱。

生命周期

可以直接导入 onXXX 一族的函数来注册生命周期钩子。它们接收的参数和返回值与对应的生命周期一致,除 onShareAppMessageonShareTimelineonAddToFavoritesonSaveExitState 外每个 onXXX 函数都能被多次调用。

page.js
js
import { definePage, onShow, onHide, onUnload } from '@vue-mini/core'

definePage({
  setup() {
    onShow(() => {
      console.log('show')
    })
    onHide(() => {
      console.log('hide')
    })
    onUnload(() => {
      console.log('unload')
    })
  },
})

这些生命周期钩子注册函数只能在 setup() 期间同步使用,其他场景下调用这些函数会被忽略并打印一个警告(开发环境)。

setup() 内同步创建的侦听器和计算状态会在页面销毁时自动删除。

  • onPageScroll

监听页面滚动会引起小程序渲染层与逻辑层的通信。为避免定义空的 onPageScroll 监听造成不必要的性能损耗,需要使用 definePage 的第二个参数提前告知 Vue Mini 是否会调用 onPageScroll() 钩子。

page.js
js
import { definePage, onPageScroll } from '@vue-mini/core'

definePage(
  {
    setup() {
      onPageScroll(({ scrollTop }) => {
        console.log('scrollTop:', scrollTop)
      })
    },
  },
  {
    listenPageScroll: true, // 默认为 false
  },
)

如果已存在另外的 onPageScroll 选项,那么可以忽略此参数。

page.js
js
import { definePage, onPageScroll } from '@vue-mini/core'

definePage({
  setup() {
    onPageScroll(({ scrollTop }) => {
      console.log('scrollTop (from setup):', scrollTop)
    })
  },
  onPageScroll({ scrollTop }) {
    console.log('scrollTop (from option):', scrollTop)
  },
})

如果以上两个条件都不满足,在 setup() 中调用 onPageScroll() 钩子会被忽略并打印一个警告(开发环境)。

  • onShareAppMessage

由于小程序会根据是否定义了 onShareAppMessage 监听来决定页面是否可以转发,所以需要使用 definePage 的第二个参数提前告知 Vue Mini 是否会调用 onShareAppMessage() 钩子。又由于 onShareAppMessage 会返回自定义转发内容,所以一个页面只能有一个 onShareAppMessage 监听。

page.js
js
import { definePage, onShareAppMessage } from '@vue-mini/core'

definePage(
  {
    setup() {
      // 仅第一次调用,且 `canShareToOthers` 为 `true`,且 `onShareAppMessage` 选项不存在时才生效。
      onShareAppMessage(() => {
        return {
          title: '自定义标题',
          path: '/my/page/path',
          imageUrl: 'https://hosts.com/my-image.png',
        }
      })
    },
  },
  {
    canShareToOthers: true, // 默认为 false
  },
)

如果条件不满足,在 setup() 中调用 onShareAppMessage() 钩子会被忽略并打印一个警告(开发环境)。

  • onShareTimeline

由于小程序会根据是否定义了 onShareTimeline 监听来决定页面是否可以分享到朋友圈,所以需要使用 definePage 的第二个参数提前告知 Vue Mini 是否会调用 onShareTimeline() 钩子。又由于 onShareTimeline 会返回自定义分享内容,所以一个页面只能有一个 onShareTimeline 监听。

page.js
js
import { definePage, onShareTimeline } from '@vue-mini/core'

definePage(
  {
    setup() {
      // 仅第一次调用,且 `canShareToTimeline` 为 `true`,且 `onShareTimeline` 选项不存在时才生效。
      onShareTimeline(() => {
        return {
          title: '自定义标题',
          query: 'a=1&b=2',
          imageUrl: 'https://hosts.com/my-image.png',
        }
      })
    },
  },
  {
    canShareToTimeline: true, // 默认为 false
  },
)

如果条件不满足,在 setup() 中调用 onShareTimeline() 钩子会被忽略并打印一个警告(开发环境)。

  • onAddToFavorites

由于 onAddToFavorites 会返回自定义收藏内容,所以一个页面只能有一个 onAddToFavorites 监听。

page.js
js
import { definePage, onAddToFavorites } from '@vue-mini/core'

definePage({
  setup() {
    // 仅第一次调用,且 `onAddToFavorites` 选项不存在才生效。
    onAddToFavorites(() => {
      return {
        title: '自定义标题',
        query: 'a=xxx&b=xxx',
        imageUrl: 'https://hosts.com/my-image.png',
      }
    })
  },
})

如果条件不满足,在 setup() 中调用 onAddToFavorites() 钩子会被忽略并打印一个警告(开发环境)。

  • onSaveExitState

由于 onSaveExitState 会返回需要保存的状态,所以一个页面只能有一个 onSaveExitState 监听。

page.js
js
import { definePage, ref, onSaveExitState } from '@vue-mini/core'

definePage({
  setup(_, context) {
    const foo = ref(context.exitState?.foo ?? '')

    // 仅第一次调用,且 `onSaveExitState` 选项不存在才生效。
    onSaveExitState(() => {
      return {
        data: { foo: 'foo' },
      }
    })

    // ...
  },
})

如果条件不满足,在 setup() 中调用 onSaveExitState() 钩子会被忽略并打印一个警告(开发环境)。

  • 生命周期对应关系

    • onLoad -> setup
    • onShow -> onShow
    • onReady -> onReady
    • onHide -> onHide
    • onUnload -> onUnload
    • onRouteDone -> onRouteDone
    • onPullDownRefresh -> onPullDownRefresh
    • onReachBottom -> onReachBottom
    • onShareAppMessage -> onShareAppMessage
    • onShareTimeline -> onShareTimeline
    • onAddToFavorites -> onAddToFavorites
    • onPageScroll -> onPageScroll
    • onResize -> onResize
    • onTabItemTap -> onTabItemTap
    • onSaveExitState -> onSaveExitState

与原生语法混用

由于 definePage()Page() 的超集,所以你也能使用原生语法。

page.js
js
import { definePage, ref } from '@vue-mini/core'

definePage({
  setup() {
    const count = ref(0)

    function increment() {
      count.value++
    }

    return { count, increment }
  },
  data: {
    number: 0,
  },
  add() {
    this.setData({ number: this.data.number + 1 })
  },
})

如果名称相同,setup() 返回的数据或方法会覆盖原生语法声明的数据或方法。你应该避免出现这种情况。

请不要在 setup() 之外访问 setup() 返回的数据或方法,这将引起混乱。如果确实有此需求,应该将相关逻辑搬到 setup() 内。

简洁语法

如果不需要使用原生语法,也可以直接传递一个 setup 函数给 definePage()

page.js
js
import { definePage, ref } from '@vue-mini/core'

definePage(() => {
  const count = ref(0)

  function increment() {
    count.value++
  }

  return { count, increment }
})

Released under the MIT License.