componentHooks.ts 3.7 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import {
2
  MINI_PROGRAM_PAGE_RUNTIME_HOOKS,
3
  once,
fxy060608's avatar
fxy060608 已提交
4 5 6 7 8 9 10 11 12 13 14
  ON_ADD_TO_FAVORITES,
  ON_HIDE,
  ON_LOAD,
  ON_PULL_DOWN_REFRESH,
  ON_REACH_BOTTOM,
  ON_READY,
  ON_RESIZE,
  ON_SHOW,
  ON_TAB_ITEM_TAP,
  ON_UNLOAD,
} from '@dcloudio/uni-shared'
15
import { hasOwn, isArray, isFunction } from '@vue/shared'
fxy060608's avatar
fxy060608 已提交
16 17 18 19 20 21 22

import { ComponentOptions } from 'vue'

import { MiniProgramAppOptions } from '../index'
import { CustomAppInstanceProperty } from './app'
import { CustomComponentInstanceProperty } from './component'

23
export const PAGE_INIT_HOOKS = [
fxy060608's avatar
fxy060608 已提交
24 25 26 27 28 29 30 31 32
  ON_LOAD,
  ON_SHOW,
  ON_HIDE,
  ON_UNLOAD,
  ON_RESIZE,
  ON_TAB_ITEM_TAP,
  ON_REACH_BOTTOM,
  ON_PULL_DOWN_REFRESH,
  ON_ADD_TO_FAVORITES,
fxy060608's avatar
fxy060608 已提交
33 34 35 36 37 38 39 40 41 42 43
  // 'onReady', // lifetimes.ready
  // 'onPageScroll', // 影响性能,开发者手动注册
  // 'onShareTimeline', // 右上角菜单,开发者手动注册
  // 'onShareAppMessage' // 右上角菜单,开发者手动注册
]

function findHooks(
  vueOptions: ComponentOptions,
  hooks = new Set<string>()
): Set<string> {
  if (vueOptions) {
44
    Object.keys(vueOptions).forEach((name) => {
fxy060608's avatar
fxy060608 已提交
45 46 47 48
      if (name.indexOf('on') === 0 && isFunction(vueOptions[name])) {
        hooks.add(name)
      }
    })
fxy060608's avatar
fxy060608 已提交
49 50 51
    if (__VUE_OPTIONS_API__) {
      const { extends: extendsOptions, mixins } = vueOptions
      if (mixins) {
52
        mixins.forEach((mixin) => findHooks(mixin, hooks))
fxy060608's avatar
fxy060608 已提交
53 54 55 56
      }
      if (extendsOptions) {
        findHooks(extendsOptions, hooks)
      }
fxy060608's avatar
fxy060608 已提交
57 58 59 60 61 62 63 64 65 66 67
    }
  }
  return hooks
}

function initHook(
  mpOptions: MiniProgramAppOptions | WechatMiniprogram.Component.MethodOption,
  hook: string,
  excludes: string[]
) {
  if (excludes.indexOf(hook) === -1 && !hasOwn(mpOptions, hook)) {
68
    mpOptions[hook] = function (
fxy060608's avatar
fxy060608 已提交
69 70 71
      this: CustomAppInstanceProperty | CustomComponentInstanceProperty,
      args: unknown
    ) {
fxy060608's avatar
fxy060608 已提交
72 73 74 75
      if (
        (__PLATFORM__ === 'mp-toutiao' || __PLATFORM__ === 'mp-lark') &&
        hook === 'onError'
      ) {
fxy060608's avatar
fxy060608 已提交
76 77 78 79 80 81 82
        return getApp().$vm.$callHook(hook, args)
      }
      return this.$vm && this.$vm.$callHook(hook, args)
    }
  }
}

fxy060608's avatar
fxy060608 已提交
83
const EXCLUDE_HOOKS = [ON_READY]
fxy060608's avatar
fxy060608 已提交
84 85 86 87 88 89

export function initHooks(
  mpOptions: MiniProgramAppOptions | WechatMiniprogram.Component.MethodOption,
  hooks: string[],
  excludes: string[] = EXCLUDE_HOOKS
) {
90
  hooks.forEach((hook) => initHook(mpOptions, hook, excludes))
fxy060608's avatar
fxy060608 已提交
91 92 93 94 95 96 97
}

export function initUnknownHooks(
  mpOptions: MiniProgramAppOptions | WechatMiniprogram.Component.MethodOption,
  vueOptions: ComponentOptions,
  excludes: string[] = EXCLUDE_HOOKS
) {
98
  findHooks(vueOptions).forEach((hook) => initHook(mpOptions, hook, excludes))
fxy060608's avatar
fxy060608 已提交
99
}
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

export function initRuntimeHooks(
  mpOptions: MiniProgramAppOptions | WechatMiniprogram.Component.MethodOption,
  runtimeHooks?: number
) {
  if (!runtimeHooks) {
    return
  }
  const hooks = Object.keys(
    MINI_PROGRAM_PAGE_RUNTIME_HOOKS
  ) as (keyof typeof MINI_PROGRAM_PAGE_RUNTIME_HOOKS)[]
  hooks.forEach((hook) => {
    if (runtimeHooks & MINI_PROGRAM_PAGE_RUNTIME_HOOKS[hook]) {
      initHook(mpOptions, hook, [])
    }
  })
}
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141

const findMixinRuntimeHooks = /*#__PURE__*/ once(() => {
  const runtimeHooks: string[] = []
  const app = getApp({ allowDefault: true })
  if (app && app.$vm && app.$vm.$) {
    const mixins = app.$vm.$.appContext.mixins as ComponentOptions[]
    if (isArray(mixins)) {
      const hooks = Object.keys(MINI_PROGRAM_PAGE_RUNTIME_HOOKS)
      mixins.forEach((mixin) => {
        hooks.forEach((hook) => {
          if (hasOwn(mixin, hook) && !runtimeHooks.includes(hook)) {
            runtimeHooks.push(hook)
          }
        })
      })
    }
  }
  return runtimeHooks
})

export function initMixinRuntimeHooks(
  mpOptions: MiniProgramAppOptions | WechatMiniprogram.Component.MethodOption
) {
  initHooks(mpOptions, findMixinRuntimeHooks())
}