# All files / src/miniprogram defineComponentHOC.ts

89.39% Statements 59/66
59.45% Branches 22/37
83.33% Functions 10/12
89.23% Lines 58/65

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x

    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x

    16x

    20x
    20x
    20x
    20x
    20x

    20x
    20x
    20x
    20x

    20x

    20x
    20x

    20x

    2x
    2x

    2x

    2x

    1x

    2x
    14x

    2x
    20x
    20x
    14x

     import { initComponents } from '../instance/components'
    import { initComputed } from '../instance/computed'
    import { config } from '../instance/config'
    import { initData } from '../instance/data'
    import { ComponentRenderProxy, Doraemon, DoraemonClass } from '../instance/init'
    import { callHook, initLifecycle } from '../instance/lifecycle'
    import { initExposed } from '../instance/expose'
    import { initMethods } from '../instance/methods'
    import { initProps } from '../instance/props'
    import { initProxy } from '../instance/proxy'
    import { initRefs } from '../instance/refs'
    import { initWatch } from '../instance/watch'
    import { setUpdatePerformance } from '../util/perf'
    import { syncPropsToData } from './syncPropsToData'

    export interface ComponentExternalOptions extends WechatMiniprogram.Component.ComponentOptions {
      /** 组件接受的外部样式类 */
      externalClasses?: string[]
      /** 组件自定义导出 */
      ['export']?: () => WechatMiniprogram.IAnyObject
      /** 组件间代码共享 */
      behaviors?: WechatMiniprogram.Behavior.BehaviorIdentifier[]
    }

    export function defineComponentHOC (externalOptions: ComponentExternalOptions = {}) {
      return function (target: DoraemonClass<Doraemon>) {
        mergeStaticProperty(externalOptions, target)

        const componentInstance = new target()
        const options = componentInstance.$options

        options.props = options.props || {}
        options.data = options.data || {}
        options.watch = options.watch || {}
        options.computed = options.computed || {}
        options.components = options.components || {}
        options.methods = options.methods || {}
        options.mixins = options.mixins || []

        const defaultProps = initProps(componentInstance, options.props)
        const defaultData = Object.keys(defaultProps).reduce((acc, name) => ({ ...acc, [name]: (defaultProps[name] as any).value }), {})
        const watch = initWatch(componentInstance, options.watch)
        const components = initComponents(componentInstance, options.components)
        const methods = initMethods(componentInstance, options.methods)
        const exposed = initExposed(componentInstance)

        const componentConf: WechatMiniprogram.Component.Options<any, any, any> = {
          options: {
            multipleSlots: typeof externalOptions.multipleSlots !== 'undefined' ?
              externalOptions.multipleSlots : true,
            addGlobalClass: typeof externalOptions.addGlobalClass !== 'undefined' ?
              externalOptions.addGlobalClass : true,
          },
          externalClasses: ['dora-class', 'dora-hover-class'].concat(
            Array.isArray(externalOptions.externalClasses) ?
              externalOptions.externalClasses : []
          ),
          ['export'] (this: ComponentRenderProxy<Doraemon>) {
            if (Object.keys(exposed).length) {
              return exposed
            }
            if (externalOptions['export']) {
              return externalOptions['export'].call(this)
            }
            return this.$component ? this.$component : this
          },
          relations: components,
          behaviors: (Array.isArray(externalOptions.behaviors) ?
            externalOptions.behaviors : []).concat(['wx://component-export', syncPropsToData(options.computed)]),
          observers: {
            ...watch,
            ['**']: function defineComputed () {
              initComputed(this.$component)
            },
          },
          properties: defaultProps,
          data: defaultDIata,
          methods,
          lifetimes: {
            created: function beforeCreate(this: ComponentRenderProxy<Doraemon>) {
              this.$component = new target()
              this.$component._render(this)
              E
              initLifecycle(this.$component, options)
              initRefs(this.$component)
              callHook(this.$component, 'beforeCreate')
            },
            attached: function created(this: ComponentRenderProxy<Doraemon>) {
              initData(tEhis.$component)
              initProxy(this.$component)
              initComputed(this.$component, true)
              if (config.performance) {
                setUpdatePerformance(this)
              }
              callHook(this.$component, 'created')
            },
            ready: function mounted(this: ComponentRenderProxy<Doraemon>) {
              if (!this.$component._isMounted) {
                this.$component._isMounted = true
              }
              callHook(this.$component, 'mounted')
            },
            detached: function destroyed(this: ComponentRenderProxy<Doraemon>) {
              if (!this.$component._isDestroyed) {
                this.$component._isDestroyed = true
              }
              callHook(this.$component, 'destroyed')
            },
            error: function errorCaptured(this: ComponentRenderProxy<Doraemon>) {
              callHook(this.$component, 'errorCaptured')
            },
          },
        }

        return Component(componentConf)
      }
    }

    function mergeStaticProperty(config: ComponentExternalOptions, target: DoraemonClass<Doraemon>) {
      for (const key in target) {
        config[key] = target[key]
      }
      // 低版本 IOS 下部分属性不能直接访问
      Object.getOwnPropertyNames(target).forEach(key => {
        const excludes = ['arguments', 'caller', 'length', 'name', 'prototype']
        if (excludes.indexOf(key) < 0) {
          config[key] = target[key]
        }
      })
    }