index.ts 6.7 KB
Newer Older
1
import { extend, invokeArrayFns, isPlainObject } from '@vue/shared'
fxy060608's avatar
fxy060608 已提交
2
import {
fxy060608's avatar
fxy060608 已提交
3
  nextTick,
fxy060608's avatar
fxy060608 已提交
4 5 6 7 8 9 10 11 12 13
  ComponentInternalInstance,
  ComponentPublicInstance,
  createBlock,
  DefineComponent,
  getCurrentInstance,
  onMounted,
  openBlock,
  onBeforeActivate,
  onBeforeDeactivate,
  onBeforeMount,
14
  onBeforeUnmount,
fxy060608's avatar
fxy060608 已提交
15
} from 'vue'
fxy060608's avatar
fxy060608 已提交
16
import { useRouter } from 'vue-router'
fxy060608's avatar
fxy060608 已提交
17 18 19 20 21 22 23 24 25
import {
  debounce,
  decodedQuery,
  ON_APP_ENTER_BACKGROUND,
  ON_APP_ENTER_FOREGROUND,
  ON_RESIZE,
  ON_WEB_INVOKE_APP_SERVICE,
  WEB_INVOKE_APPSERVICE,
} from '@dcloudio/uni-shared'
fxy060608's avatar
fxy060608 已提交
26
import { injectAppLaunchHooks } from '@dcloudio/uni-api'
27
import { subscribeViewMethod, unsubscribeViewMethod } from '@dcloudio/uni-core'
fxy060608's avatar
fxy060608 已提交
28 29
import { LayoutComponent } from '../..'
import { initApp } from './app'
fxy060608's avatar
fxy060608 已提交
30
import { initPage, onPageShow, onPageReady } from './page'
fxy060608's avatar
fxy060608 已提交
31
import { usePageMeta, usePageRoute } from './provide'
32
import { initLaunchOptions, getEnterOptions } from './utils'
fxy060608's avatar
fxy060608 已提交
33 34 35

interface SetupComponentOptions {
  init: (vm: ComponentPublicInstance) => void
fxy060608's avatar
fxy060608 已提交
36 37 38 39 40
  setup: (instance: ComponentInternalInstance) => Record<string, unknown> | void
  afterSetup?: (
    instance: ComponentInternalInstance,
    query: Record<string, unknown>
  ) => void
fxy060608's avatar
fxy060608 已提交
41
  before?: (comp: DefineComponent) => void
fxy060608's avatar
fxy060608 已提交
42 43 44 45
}

function wrapperComponentSetup(
  comp: DefineComponent,
fxy060608's avatar
fxy060608 已提交
46
  { init, setup, before, afterSetup }: SetupComponentOptions
fxy060608's avatar
fxy060608 已提交
47
) {
fxy060608's avatar
fxy060608 已提交
48
  before && before(comp)
fxy060608's avatar
fxy060608 已提交
49 50 51 52
  const oldSetup = comp.setup
  comp.setup = (props, ctx) => {
    const instance = getCurrentInstance()!
    init(instance.proxy!)
fxy060608's avatar
fxy060608 已提交
53
    const query = setup(instance)
fxy060608's avatar
fxy060608 已提交
54
    if (oldSetup) {
fxy060608's avatar
fxy060608 已提交
55
      return oldSetup(query || props, ctx)
fxy060608's avatar
fxy060608 已提交
56
    }
fxy060608's avatar
fxy060608 已提交
57 58 59
    if (afterSetup) {
      afterSetup(instance, query!)
    }
fxy060608's avatar
fxy060608 已提交
60 61 62 63 64 65 66 67 68 69 70 71
  }
}

function setupComponent(comp: any, options: SetupComponentOptions) {
  if (comp && (comp.__esModule || comp[Symbol.toStringTag] === 'Module')) {
    wrapperComponentSetup(comp.default, options)
  } else {
    wrapperComponentSetup(comp, options)
  }
  return comp
}

fxy060608's avatar
fxy060608 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84
export function setupWindow(comp: any, id: number) {
  return setupComponent(comp, {
    init: (vm) => {
      vm.$page = {
        id,
      } as Page.PageInstance['$page']
    },
    setup(instance) {
      instance.root = instance // windows 中组件 root 指向 window
    },
  })
}

fxy060608's avatar
fxy060608 已提交
85 86 87
export function setupPage(comp: any) {
  return setupComponent(comp, {
    init: initPage,
fxy060608's avatar
fxy060608 已提交
88 89 90 91 92
    afterSetup(instance, query) {
      // 因为 onLoad 是在 setup 执行过程中添加的,故需要放在 after 中执行
      const { onLoad } = instance
      onLoad && invokeArrayFns(onLoad, decodedQuery(query))
    },
fxy060608's avatar
fxy060608 已提交
93
    setup(instance) {
fxy060608's avatar
fxy060608 已提交
94
      instance.root = instance // 组件 root 指向页面
fxy060608's avatar
fxy060608 已提交
95
      const route = usePageRoute()
fxy060608's avatar
fxy060608 已提交
96
      // node环境仅触发Page onLoad生命周期
fxy060608's avatar
fxy060608 已提交
97
      if (__NODE_JS__) {
fxy060608's avatar
fxy060608 已提交
98 99 100 101
        nextTick(() => {
          const { onLoad } = instance
          onLoad && invokeArrayFns(onLoad, decodedQuery(route.query))
        })
fxy060608's avatar
fxy060608 已提交
102 103
        return route.query
      }
fxy060608's avatar
fxy060608 已提交
104
      const pageMeta = usePageMeta()
105
      onMounted(() => {
fxy060608's avatar
fxy060608 已提交
106
        // 放在 onMounted 中,可以保证子组件中监听的相关生命周期也可以触发,比如onShow,onPageScroll
fxy060608's avatar
fxy060608 已提交
107
        onPageShow(instance, pageMeta)
fxy060608's avatar
fxy060608 已提交
108
        const { onShow } = instance
fxy060608's avatar
fxy060608 已提交
109
        instance.__isVisible = true
110
        onShow && invokeArrayFns(onShow)
fxy060608's avatar
fxy060608 已提交
111 112
      })
      onMounted(() => {
fxy060608's avatar
fxy060608 已提交
113
        onPageReady(instance)
fxy060608's avatar
fxy060608 已提交
114
        const { onReady } = instance
115
        onReady && invokeArrayFns(onReady)
fxy060608's avatar
fxy060608 已提交
116 117 118
      })
      onBeforeActivate(() => {
        if (!instance.__isVisible) {
fxy060608's avatar
fxy060608 已提交
119
          onPageShow(instance, pageMeta)
fxy060608's avatar
fxy060608 已提交
120 121 122 123 124 125 126 127 128 129 130 131
          instance.__isVisible = true
          const { onShow } = instance
          onShow && invokeArrayFns(onShow)
        }
      })
      onBeforeDeactivate(() => {
        if (instance.__isVisible && !instance.__isUnload) {
          instance.__isVisible = false
          const { onHide } = instance
          onHide && invokeArrayFns(onHide)
        }
      })
fxy060608's avatar
fxy060608 已提交
132

133 134 135 136 137
      subscribeViewMethod(pageMeta.id!)
      onBeforeUnmount(() => {
        unsubscribeViewMethod(pageMeta.id!)
      })

fxy060608's avatar
fxy060608 已提交
138
      return route.query
fxy060608's avatar
fxy060608 已提交
139 140 141 142 143 144 145 146
    },
  })
}

export function setupApp(comp: any) {
  return setupComponent(comp, {
    init: initApp,
    setup(instance) {
fxy060608's avatar
fxy060608 已提交
147
      const route = usePageRoute()
fxy060608's avatar
fxy060608 已提交
148 149 150 151
      // node环境不触发App生命周期
      if (__NODE_JS__) {
        return route.query
      }
fxy060608's avatar
fxy060608 已提交
152
      const onLaunch = () => {
fxy060608's avatar
fxy060608 已提交
153
        const { onLaunch, onShow, onPageNotFound } = instance
fxy060608's avatar
fxy060608 已提交
154
        const path = route.path.substr(1)
155 156 157 158 159 160 161 162 163
        const launchOptions = extend(
          {
            app: { mixin: instance.appContext.app.mixin },
          },
          initLaunchOptions({
            path: path || __uniRoutes[0].meta.route,
            query: decodedQuery(route.query),
          })
        )
fxy060608's avatar
fxy060608 已提交
164 165
        onLaunch && invokeArrayFns(onLaunch, launchOptions)
        onShow && invokeArrayFns(onShow, launchOptions)
fxy060608's avatar
fxy060608 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178
        if (__UNI_FEATURE_PAGES__) {
          if (!route.matched.length) {
            const pageNotFoundOptions = {
              notFound: true,
              openType: 'appLaunch',
              path: route.path,
              query: {},
              scene: 1001,
            }
            onPageNotFound &&
              invokeArrayFns(onPageNotFound, pageNotFoundOptions)
          }
        }
fxy060608's avatar
fxy060608 已提交
179
      }
fxy060608's avatar
fxy060608 已提交
180
      injectAppLaunchHooks(instance)
fxy060608's avatar
fxy060608 已提交
181 182 183 184 185 186
      if (__UNI_FEATURE_PAGES__) {
        // 等待ready后,再onLaunch,可以顺利获取到正确的path和query
        useRouter().isReady().then(onLaunch)
      } else {
        onBeforeMount(onLaunch)
      }
fxy060608's avatar
fxy060608 已提交
187
      onMounted(() => {
fxy060608's avatar
fxy060608 已提交
188 189 190
        window.addEventListener('resize', debounce(onResize, 50))
        window.addEventListener('message', onMessage)
        document.addEventListener('visibilitychange', onVisibilityChange)
fxy060608's avatar
fxy060608 已提交
191
      })
fxy060608's avatar
fxy060608 已提交
192
      return route.query
fxy060608's avatar
fxy060608 已提交
193
    },
fxy060608's avatar
fxy060608 已提交
194
    before(comp) {
fxy060608's avatar
fxy060608 已提交
195
      comp.mpType = 'app'
fxy060608's avatar
fxy060608 已提交
196 197 198
      comp.setup = () => () => {
        return openBlock(), createBlock(LayoutComponent)
      }
fxy060608's avatar
fxy060608 已提交
199 200 201
    },
  })
}
fxy060608's avatar
fxy060608 已提交
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229

function onResize() {
  const { windowWidth, windowHeight, screenWidth, screenHeight } =
    uni.getSystemInfoSync()
  const landscape = Math.abs(Number(window.orientation)) === 90
  const deviceOrientation = landscape ? 'landscape' : 'portrait'
  UniServiceJSBridge.emit(ON_RESIZE, {
    deviceOrientation,
    size: {
      windowWidth,
      windowHeight,
      screenWidth,
      screenHeight,
    },
  })
}
function onMessage(evt: {
  data?: { type: string; data: any; pageId: number }
}) {
  if (isPlainObject(evt.data) && evt.data.type === WEB_INVOKE_APPSERVICE) {
    UniServiceJSBridge.emit(
      ON_WEB_INVOKE_APP_SERVICE,
      evt.data.data,
      evt.data.pageId
    )
  }
}
function onVisibilityChange() {
230 231 232 233 234 235
  const { emit } = UniServiceJSBridge
  if (document.visibilityState === 'visible') {
    emit(ON_APP_ENTER_FOREGROUND, getEnterOptions())
  } else {
    emit(ON_APP_ENTER_BACKGROUND)
  }
fxy060608's avatar
fxy060608 已提交
236
}