import { isFn, cached, camelize, hasOwn } from 'uni-shared' import { handleLink as handleBaseLink, toSkip } from '../../../mp-weixin/runtime/wrapper/util' import deepEqual from './deep-equal' export { markMPComponent } from '../../../mp-weixin/runtime/wrapper/util' const customizeRE = /:/g const customize = cached((str) => { return camelize(str.replace(customizeRE, '-')) }) export const isComponent2 = my.canIUse('component2') export const mocks = ['$id'] export function initRefs () { } export function initBehavior ({ properties }) { const props = {} Object.keys(properties).forEach(key => { props[key] = properties[key].value }) return { props } } export function initRelation (detail) { this.props.onVueInit(detail) } export function initSpecialMethods (mpInstance) { if (!mpInstance.$vm) { return } let path = mpInstance.is || mpInstance.route if (!path) { return } if (path.indexOf('/') === 0) { path = path.substr(1) } const specialMethods = my.specialMethods && my.specialMethods[path] if (specialMethods) { specialMethods.forEach(method => { if (isFn(mpInstance.$vm[method])) { mpInstance[method] = function (event) { if (hasOwn(event, 'markerId')) { event.detail = typeof event.detail === 'object' ? event.detail : {} event.detail.markerId = event.markerId } // TODO normalizeEvent mpInstance.$vm[method](event) } } }) } } export function initChildVues (mpInstance) { // 此时需保证当前 mpInstance 已经存在 $vm if (!mpInstance.$vm) { return } mpInstance._$childVues && mpInstance._$childVues.forEach(({ vuePid, vueOptions, VueComponent, mpInstance: childMPInstance }) => { // 父子关系 handleBaseLink.call(mpInstance, { detail: { vuePid, vueOptions } }) childMPInstance.$vm = new VueComponent(vueOptions) initSpecialMethods(childMPInstance) handleRef.call(vueOptions.parent.$scope, childMPInstance) childMPInstance.$vm.$mount() initChildVues(childMPInstance) childMPInstance.$vm._isMounted = true childMPInstance.$vm.__call_hook('mounted') childMPInstance.$vm.__call_hook('onReady') }) delete mpInstance._$childVues } export function handleProps (ref) { const eventProps = {} let refProps = ref.props const eventList = (refProps['data-event-list'] || '').split(',') // 初始化支付宝小程序组件事件 eventList.forEach(key => { const handler = refProps[key] const res = key.match(/^on([A-Z])(\S*)/) const event = res && (res[1].toLowerCase() + res[2]) refProps[key] = eventProps[key] = function () { const props = Object.assign({}, refProps) props[key] = handler // 由于支付宝事件可能包含多个参数,不使用微信小程序事件格式 delete props['data-com-type'] triggerEvent.bind({ props })(event, { __args__: [...arguments] }) } }) // 处理 props 重写 Object.defineProperty(ref, 'props', { get () { return refProps }, set (value) { refProps = Object.assign(value, eventProps) } }) } export function handleRef (ref) { if (!(ref && this.$vm)) { return } const refName = ref.props['data-ref'] const refInForName = ref.props['data-ref-in-for'] if (refName) { this.$vm.$refs[refName] = ref.$vm || toSkip(ref) } else if (refInForName) { (this.$vm.$refs[refInForName] || (this.$vm.$refs[refInForName] = [])).push(ref.$vm || toSkip(ref)) } } export function triggerEvent (type, detail, options) { const handler = this.props && this.props[customize('on-' + type)] if (!handler) { return } const eventOpts = this.props['data-event-opts'] const eventParams = this.props['data-event-params'] const comType = this.props['data-com-type'] const target = { dataset: { eventOpts, eventParams, comType } } handler({ type: customize(type), target, currentTarget: target, detail }) } const IGNORES = ['$slots', '$scopedSlots'] export function createObserver (isDidUpdate) { return function observe (props) { const prevProps = isDidUpdate ? props : this.props const nextProps = isDidUpdate ? this.props : props if (deepEqual(prevProps, nextProps)) { return } Object.keys(prevProps).forEach(name => { if (IGNORES.indexOf(name) === -1) { const prevValue = prevProps[name] const nextValue = nextProps[name] if (!isFn(prevValue) && !isFn(nextValue) && !deepEqual(prevValue, nextValue)) { this.$vm[name] = nextProps[name] } } }) } } export const handleLink = (function () { if (isComponent2) { return function handleLink (detail) { return handleBaseLink.call(this, { detail }) } } return function handleLink (detail) { if (this.$vm && this.$vm._isMounted) { // 父已初始化 return handleBaseLink.call(this, { detail: { vuePid: detail.vuePid, vueOptions: detail.vueOptions } }) } // 支付宝通过 didMount 来实现,先子后父,故等父 ready 之后,统一初始化 (this._$childVues || (this._$childVues = [])).unshift(detail) } })() export const handleWrap = function (mp, destory) { const vueId = mp.props.vueId const list = (mp.props['data-event-list'] || '').split(',') list.forEach(eventName => { const key = `${eventName}${vueId}` if (destory) { delete this[key] } else { this[key] = function () { mp.props[eventName].apply(this, arguments) } } }) if (!destory) { handleProps(mp) } }