util.js 4.0 KB
Newer Older
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
import {
  isFn,
  noop,
  isPlainObject
} from 'uni-shared'

export function initHooks (mpOptions, hooks) {
  hooks.forEach(hook => {
    mpOptions[hook] = function (args) {
      this.$vm.__call_hook(hook, args)
    }
  })
}

export function initMethods (mpOptions, vueOptions) {
//   if (vueOptions.methods) {
//     Object.assign(mpOptions, vueOptions.methods)
//   }
}

export function getData (data) {
  if (typeof data === 'function') {
    try {
      return data()
    } catch (e) {
      console.warn('根据 Vue 的 data 函数初始化小程序 data 失败,请尽量确保 data 函数中不访问 vm 对象,否则可能影响首次数据渲染速度。')
    }
    return {}
  }
  return data || {}
}

const PROP_TYPES = [String, Number, Boolean, Object, Array, null]

export function getProperties (props) {
  const properties = {}
  if (Array.isArray(props)) { // ['title']
    props.forEach(key => {
      properties[key] = null
    })
  } else if (isPlainObject(props)) { // {title:{type:String,default:''},content:String}
    Object.keys(props).forEach(key => {
      const opts = props[key]
      if (isPlainObject(opts)) { // title:{type:String,default:''}
        let value = opts['default']
        if (isFn(value)) {
          value = value()
        }
        properties[key] = {
          type: PROP_TYPES.includes(opts.type) ? opts.type : null,
          value
        }
      } else { // content:String
        properties[key] = PROP_TYPES.includes(opts) ? opts : null
      }
    })
  }
  return properties
}

function wrapper (event) {
  event.stopPropagation = noop
  event.preventDefault = noop

  event.target = event.target || {}
  event.detail = event.detail || {}
  // TODO 又得兼容 mpvue 的 mp 对象
  event.mp = event
  event.target = Object.assign({}, event.target, event.detail)
  return event
}

function processEventArgs (event, args = [], isCustom) {
  if (isCustom && !args.length) { // 无参数,直接传入 detail 数组
    return event.detail
  }
  const ret = []
  args.forEach(arg => {
    if (arg === '$event') {
      ret.push(isCustom ? event.detail[0] : event)
    } else {
      ret.push(arg)
    }
  })

  return ret
}

const ONCE = '~'
const CUSTOM = '^'

export function handleEvent (event) {
  event = wrapper(event)

  // [['tap',[['handle',[1,2,a]],['handle1',[1,2,a]]]]]
  const eventOpts = (event.currentTarget || event.target).dataset.eventOpts
  if (!eventOpts) {
    return console.warn(`事件信息不存在`)
  }

  // [['handle',[1,2,a]],['handle1',[1,2,a]]]
  const eventType = event.type
  eventOpts.forEach(eventOpt => {
    let type = eventOpt[0]
    const eventsArray = eventOpt[1]

    const isCustom = type.charAt(0) === CUSTOM
    type = isCustom ? type.slice(1) : type
    const isOnce = type.charAt(0) === ONCE
    type = isOnce ? type.slice(1) : type

    if (eventsArray && eventType === type) {
      eventsArray.forEach(eventArray => {
        const handler = this.$vm[eventArray[0]]
        if (isOnce) {
          if (handler.once) {
            return
          }
          handler.once = true
        }
        handler.apply(this.$vm, processEventArgs(event, eventArray[1], isCustom))
      })
    }
  })
}

export function handleLink (event) {
  event.detail.$parent = this.$vm
}

export function initRefs (vm) {
  const mpInstance = vm.$mp[vm.mpType]
  Object.defineProperty(vm, '$refs', {
    get () {
      const $refs = Object.create(null)
      const components = mpInstance.selectAllComponents('.__ref__')
      components.forEach(component => {
        const id = component.id
        $refs[id] = component.$vm
      })
      const forComponents = mpInstance.selectAllComponents('.__ref-in-for__')
      forComponents.forEach(component => {
        const id = component.id
        if (!$refs[id]) {
          $refs[id] = []
        }
        $refs[id].push(component.$vm)
      })
      return $refs
    }
  })
}