componentProps.ts 3.6 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2 3 4 5 6
import { ComponentPropsOptions } from 'vue'
import { isArray, isPlainObject, isFunction } from '@vue/shared'
import { MPComponentOptions, MPComponentInstance } from './component'

import Component = WechatMiniprogram.Component

fxy060608's avatar
fxy060608 已提交
7
const PROP_TYPES = [String, Number, Boolean, Object, Array, null]
fxy060608's avatar
fxy060608 已提交
8 9 10 11 12 13 14 15 16

function createObserver(name: string) {
  return function observer(this: MPComponentInstance, newVal: unknown) {
    if (this.$vm) {
      this.$vm.$.props[name] = newVal // 为了触发其他非 render watcher
    }
  }
}

fxy060608's avatar
fxy060608 已提交
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
function parsePropType(type: unknown, defaultValue: unknown) {
  // [String]=>String
  if (isArray(type) && type.length === 1) {
    return type[0]
  }
  if (__PLATFORM__ === 'mp-baidu') {
    if (
      // [String,Boolean]=>Boolean
      defaultValue === false &&
      isArray(type) &&
      type.length === 2 &&
      type.indexOf(String) !== -1 &&
      type.indexOf(Boolean) !== -1
    ) {
      return Boolean
    }
  }
  return type
}

function normalizePropType(type: unknown, defaultValue: unknown) {
  if (__PLATFORM__ === 'mp-weixin') {
    // 不再生成具体的 type 类型,因为微信首次初始化,值为 undefined 时,会告警:property received type-uncompatible value
    return null
  }
  const res = parsePropType(type, defaultValue)
  return PROP_TYPES.indexOf(res) !== -1 ? res : null
}
fxy060608's avatar
fxy060608 已提交
45 46 47 48

function initDefaultProps(isBehavior: boolean = false) {
  const properties: Component.PropertyOption = {}
  if (!isBehavior) {
fxy060608's avatar
fxy060608 已提交
49
    if (__PLATFORM__ === 'mp-baidu' || __PLATFORM__ === 'mp-kuaishou') {
fxy060608's avatar
fxy060608 已提交
50 51 52 53 54 55 56
      // 百度小程序自定义组件不支持绑定动态事件,动态dataset,故通过props传递事件信息
      // event-opts
      properties.eO = {
        type: null,
        value: '',
      }
    }
fxy060608's avatar
fxy060608 已提交
57
    properties.vI = {
fxy060608's avatar
fxy060608 已提交
58
      type: null, // 均不指定类型,避免 property received type-uncompatible value 警告
59
      value: '',
fxy060608's avatar
fxy060608 已提交
60 61
    }
    // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
fxy060608's avatar
fxy060608 已提交
62
    properties.vS = {
fxy060608's avatar
fxy060608 已提交
63 64
      type: null,
      value: [],
65
      observer: function (this: MPComponentInstance, newVal) {
fxy060608's avatar
fxy060608 已提交
66 67 68 69 70
        const $slots = Object.create(null)
        newVal.forEach((slotName: string) => {
          $slots[slotName] = true
        })
        this.setData({
71
          $slots,
fxy060608's avatar
fxy060608 已提交
72
        })
73
      },
fxy060608's avatar
fxy060608 已提交
74 75 76 77 78 79 80 81 82 83 84 85 86
    }
  }
  return properties
}

function createProperty(key: string, prop: any) {
  if (__PLATFORM__ === 'mp-alipay') {
    return prop
  }
  prop.observer = createObserver(key)
  return prop
}

fxy060608's avatar
fxy060608 已提交
87
/**
fxy060608's avatar
fxy060608 已提交
88
 *
fxy060608's avatar
fxy060608 已提交
89 90 91 92
 * @param mpComponentOptions
 * @param rawProps
 * @param isBehavior
 */
fxy060608's avatar
fxy060608 已提交
93 94 95 96 97 98 99 100
export function initProps(
  mpComponentOptions: MPComponentOptions,
  rawProps: ComponentPropsOptions | null,
  isBehavior: boolean = false
) {
  const properties = initDefaultProps(isBehavior)

  if (isArray(rawProps)) {
101
    rawProps.forEach((key) => {
fxy060608's avatar
fxy060608 已提交
102
      properties[key] = createProperty(key, {
103
        type: null,
fxy060608's avatar
fxy060608 已提交
104 105 106
      })
    })
  } else if (isPlainObject(rawProps)) {
107
    Object.keys(rawProps).forEach((key) => {
fxy060608's avatar
fxy060608 已提交
108 109 110 111 112 113 114
      const opts = rawProps[key]
      if (isPlainObject(opts)) {
        // title:{type:String,default:''}
        let value = (opts as any).default
        if (isFunction(value)) {
          value = value()
        }
fxy060608's avatar
fxy060608 已提交
115 116
        const type = (opts as any).type as any
        ;(opts as any).type = normalizePropType(type, value)
fxy060608's avatar
fxy060608 已提交
117
        properties[key] = createProperty(key, {
fxy060608's avatar
fxy060608 已提交
118
          type: (opts as any).type,
119
          value,
fxy060608's avatar
fxy060608 已提交
120 121 122 123
        })
      } else {
        // content:String
        properties[key] = createProperty(key, {
fxy060608's avatar
fxy060608 已提交
124
          type: normalizePropType(opts, null),
fxy060608's avatar
fxy060608 已提交
125 126 127 128 129 130 131
        })
      }
    })
  }

  mpComponentOptions.properties = properties
}