diff --git a/packages/uni-mp-alipay/dist/index.js b/packages/uni-mp-alipay/dist/index.js index bcb0d824cc489073924099b6a2939df188772b3c..e61a008d2c6e44ddd531440cb57e47c3105cdd7d 100644 --- a/packages/uni-mp-alipay/dist/index.js +++ b/packages/uni-mp-alipay/dist/index.js @@ -2478,11 +2478,12 @@ function handleRef (ref) { if (ref.props['data-com-type'] === 'wx') { const eventProps = {}; let refProps = ref.props; + const eventList = refProps['data-event-list'].split(','); // 初始化支付宝小程序组件事件 Object.keys(refProps).forEach(key => { - const handler = refProps[key]; - const res = key.match(/^on([A-Z])(\S*)/); - if (res && typeof handler === 'function' && handler.name === 'bound handleEvent') { + if (eventList.includes(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); @@ -2581,7 +2582,23 @@ const handleLink$1 = (function () { // 支付宝通过 didMount 来实现,先子后父,故等父 ready 之后,统一初始化 (this._$childVues || (this._$childVues = [])).unshift(detail); } -})(); +})(); + +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 { + // TODO remove handleRef + this[key] = function () { + mp.props[eventName].apply(this, arguments); + }; + } + }); +}; function parseApp (vm) { Object.defineProperty(Vue.prototype, '$slots', { @@ -2744,6 +2761,7 @@ function parsePage (vuePageOptions) { __r: handleRef, __e: handleEvent, __l: handleLink$1, + __w: handleWrap, triggerEvent }; @@ -2860,6 +2878,7 @@ function parseComponent (vueComponentOptions) { __r: handleRef, __e: handleEvent, __l: handleLink$1, + __w: handleWrap, triggerEvent } }; @@ -2871,14 +2890,14 @@ function parseComponent (vueComponentOptions) { componentOptions.deriveDataFromProps = createObserver$1(); } else { componentOptions.didUpdate = createObserver$1(true); - } - - if (Array.isArray(vueOptions.wxsCallMethods)) { - vueOptions.wxsCallMethods.forEach(callMethod => { - componentOptions.methods[callMethod] = function (args) { - return this.$vm[callMethod](args) - }; - }); + } + + if (Array.isArray(vueOptions.wxsCallMethods)) { + vueOptions.wxsCallMethods.forEach(callMethod => { + componentOptions.methods[callMethod] = function (args) { + return this.$vm[callMethod](args) + }; + }); } return componentOptions diff --git a/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js b/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js index f178bf23f0df12d0bd982a18dd64dbcc72ec476b..47a77a431da88ab48638069e658d680dd54c8392 100644 --- a/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js +++ b/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js @@ -46,8 +46,8 @@ describe('mp:compiler-mp-alipay', () => { '' ) assertCodegen( - 'text', - 'text', + 'text', + 'text', undefined, undefined, { @@ -55,8 +55,8 @@ describe('mp:compiler-mp-alipay', () => { } ) assertCodegen( - 'text', - 'text', + 'text', + 'text', undefined, undefined, { diff --git a/packages/uni-template-compiler/lib/constants.js b/packages/uni-template-compiler/lib/constants.js index bc38a000a1f3b1dc73d8e219e346754a317cf888..8d35520f701e2f9fba1146bde2b4539f70bc9d37 100644 --- a/packages/uni-template-compiler/lib/constants.js +++ b/packages/uni-template-compiler/lib/constants.js @@ -28,6 +28,7 @@ const INTERNAL_GET_EVENT = '__get_event' const INTERNAL_GET_REFS = '__get_refs' const INTERNAL_EVENT_PROXY = '__e' const INTERNAL_EVENT_LINK = '__l' +const INTERNAL_EVENT_WRAP = '__w' const ALLOWED_GLOBAL_OBJECT = [ 'Math', @@ -63,6 +64,7 @@ module.exports = { ATTR_DATA_EVENT_OPTS: 'data-event-opts', ATTR_DATA_COM_TYPE: 'data-com-type', ATTR_DATA_EVENT_PARAMS: 'data-event-params', + ATTR_DATA_EVENT_LIST: 'data-event-list', ATTE_DATA_CUSTOM_HIDDEN: 'data-custom-hidden', INTERNAL_GET_ORIG, INTERNAL_GET_CLASS, @@ -71,6 +73,7 @@ module.exports = { INTERNAL_GET_REFS, INTERNAL_EVENT_PROXY, INTERNAL_EVENT_LINK, + INTERNAL_EVENT_WRAP, INTERNAL_SET_MODEL, INTERNAL_SET_SYNC, METHOD_BUILT_IN: [ diff --git a/packages/uni-template-compiler/lib/script/traverse/data/index.js b/packages/uni-template-compiler/lib/script/traverse/data/index.js index f1936216860004d9e9cf11849b5e78ccd29e8baa..1f78c491f08deec57ec988cf3299347742b4cd83 100644 --- a/packages/uni-template-compiler/lib/script/traverse/data/index.js +++ b/packages/uni-template-compiler/lib/script/traverse/data/index.js @@ -1,7 +1,13 @@ const t = require('@babel/types') const { - ATTR_DATA_COM_TYPE + METHOD_CREATE_ELEMENT, + ATTR_DATA_EVENT_OPTS, + ATTR_DATA_COM_TYPE, + ATTR_DATA_EVENT_LIST, + ATTR_DATA_EVENT_PARAMS, + ATTE_DATA_CUSTOM_HIDDEN, + INTERNAL_EVENT_WRAP } = require('../../../constants') const processRef = require('./ref') @@ -37,7 +43,8 @@ module.exports = function traverseData (path, state, tagName) { }) // 该组件是引入的小程序组件 - if (state.options.wxComponents[tagName]) { + const wxComponent = state.options.wxComponents[tagName] + if (wxComponent) { addAttrProperties.push( t.objectProperty( t.stringLiteral(ATTR_DATA_COM_TYPE), @@ -51,6 +58,81 @@ module.exports = function traverseData (path, state, tagName) { t.stringLiteral('__r') ) ) + const properties = path.node.properties.find(prop => prop.key.name === 'on').value.properties + const list = [] + for (let index = 0; index < properties.length; index++) { + const element = properties[index] + if (element.value.value === '__e') { + list.push(element.key.value) + } + } + addAttrProperties.push( + t.objectProperty( + t.stringLiteral(ATTR_DATA_EVENT_LIST), + t.stringLiteral(list.join(',')) + ) + ) + if (wxComponent.startsWith('plugin://')) { + const wrapperTag = 'plugin-wrapper' + const orgPath = path.parentPath + const orgNode = orgPath.node + const args = orgNode.arguments + const orgTag = args[0] + orgTag.$mpPlugin = true + args[0] = t.stringLiteral(wrapperTag) + const orgOptions = args[1] + const orgOptionsProps = orgOptions.properties + const targetAttrs = [] + const targetOptionsProps = [ + t.objectProperty(t.identifier('attrs'), t.objectExpression(targetAttrs)) + ] + const uniAttrs = [ + ATTR_DATA_EVENT_OPTS, + ATTR_DATA_COM_TYPE, + ATTR_DATA_EVENT_PARAMS, + ATTR_DATA_EVENT_LIST, + ATTE_DATA_CUSTOM_HIDDEN, + 'vue-id' + ] + for (let a = orgOptionsProps.length - 1; a >= 0; a--) { + const prop = orgOptionsProps[a] + if (prop.key.name === 'attrs') { + const attrs = prop.value.properties + for (let b = attrs.length - 1; b >= 0; b--) { + const element = attrs[b] + const key = element.key.value + if (!uniAttrs.includes(key)) { + attrs.splice(b, 1) + targetAttrs.push(element) + } + } + attrs.push(t.objectProperty(t.stringLiteral('onPluginWrap'), t.stringLiteral(INTERNAL_EVENT_WRAP))) + } else if (prop.key.name === 'on') { + const ons = prop.value.properties + ons.forEach(item => { + const attrs = path.node.properties.find(prop => prop.key.name === 'attrs').value.properties + const vueId = attrs.find(prop => prop.key.value === 'vue-id').value + const eventName = item.key.value + targetAttrs.push(t.objectProperty(t.stringLiteral(eventName), t.binaryExpression('+', t.stringLiteral(eventName), vueId))) + }) + } else { + orgOptionsProps.splice(a, 1) + targetOptionsProps.push(prop) + } + } + const orgChild = args[2] + const targetOptions = t.objectExpression(targetOptionsProps) + targetOptions.$mpProcessed = true + const targetArguments = [ + orgTag, + targetOptions + ] + if (orgChild) { + targetArguments.push(orgChild) + } + const targetNode = t.callExpression(t.identifier(METHOD_CREATE_ELEMENT), targetArguments) + args[2] = targetNode + } } } diff --git a/packages/uni-template-compiler/lib/script/traverse/visitor.js b/packages/uni-template-compiler/lib/script/traverse/visitor.js index 572149fe79aaa0ede9fb549e684285d8246fc97d..bec219549cb607ac8c30b56e308d17465b2dba4b 100644 --- a/packages/uni-template-compiler/lib/script/traverse/visitor.js +++ b/packages/uni-template-compiler/lib/script/traverse/visitor.js @@ -167,7 +167,8 @@ module.exports = { tagNode.value = getComponentName(hyphenate(tagName)) // 组件增加 vueId - if (this.options.platform.isComponent(tagNode.value)) { + // 跳过支付宝插件组件 + if (this.options.platform.isComponent(tagNode.value) && !tagNode.$mpPlugin) { addVueId(path, this) } diff --git a/packages/webpack-uni-mp-loader/lib/plugin/generate-component.js b/packages/webpack-uni-mp-loader/lib/plugin/generate-component.js index e52a14a7443e66ae287c73f0d10c16962e02d774..73fcbaa03408fdd4c85824609fe14a61807a2efe 100644 --- a/packages/webpack-uni-mp-loader/lib/plugin/generate-component.js +++ b/packages/webpack-uni-mp-loader/lib/plugin/generate-component.js @@ -236,6 +236,42 @@ module.exports = function generateComponent (compilation, jsonpFunction = 'webpa }) } } + // fix mp-alipay plugin + if (process.env.UNI_PLATFORM === 'mp-alipay' && appJsonFile) { + const obj = JSON.parse(appJsonFile.source()) + if (obj && obj.usingComponents && !Object.keys(obj.usingComponents).length) { + const componentName = 'plugin-wrapper' + obj.usingComponents[componentName] = `/${componentName}` + const source = JSON.stringify(obj, null, 2) + appJsonFile.source = function () { + return source + } + const files = [ + { + ext: 'axml', + source: '' + }, + { + ext: 'js', + source: 'Component({onInit(){this.props.onPluginWrap(this)},didUnmount(){this.props.onPluginWrap(this,false)}})' + }, + { + ext: 'json', + source: '{"component":true}' + } + ] + files.forEach(({ ext, source }) => { + compilation.assets[`${componentName}.${ext}`] = { + size () { + return Buffer.byteLength(source, 'utf8') + }, + source () { + return source + } + } + }) + } + } if (process.env.UNI_FEATURE_OBSOLETE !== 'false') { if (lastComponents.length) { for (const name of lastComponents) { diff --git a/packages/webpack-uni-mp-loader/lib/plugin/generate-json.js b/packages/webpack-uni-mp-loader/lib/plugin/generate-json.js index 493b6f4779bbb4599eab92ab4d987747da09e78b..2fe7b1acd4141dc013051e6101fb31d651c20c06 100644 --- a/packages/webpack-uni-mp-loader/lib/plugin/generate-json.js +++ b/packages/webpack-uni-mp-loader/lib/plugin/generate-json.js @@ -154,6 +154,14 @@ module.exports = function generateJson (compilation) { } }) } + // fix mp-alipay plugin + if (process.env.UNI_PLATFORM === 'mp-alipay') { + const usingComponents = jsonObj.usingComponents || {} + if (Object.values(usingComponents).find(value => value.startsWith('plugin://'))) { + const componentName = 'plugin-wrapper' + usingComponents[componentName] = '/' + componentName + } + } if (jsonObj.genericComponents && jsonObj.genericComponents.length) { // scoped slots // 生成genericComponents json diff --git a/src/platforms/mp-alipay/runtime/wrapper/component-parser.js b/src/platforms/mp-alipay/runtime/wrapper/component-parser.js index 3bb329d0179e27ba75a4117119c9862de596a58f..5dc4c94cf2be066c55a47a34e7cbacf02e95d0dc 100644 --- a/src/platforms/mp-alipay/runtime/wrapper/component-parser.js +++ b/src/platforms/mp-alipay/runtime/wrapper/component-parser.js @@ -12,6 +12,7 @@ import { import { handleRef, handleLink, + handleWrap, initBehavior, initRelation, triggerEvent, @@ -115,6 +116,7 @@ export default function parseComponent (vueComponentOptions) { __r: handleRef, __e: handleEvent, __l: handleLink, + __w: handleWrap, triggerEvent } } @@ -126,15 +128,15 @@ export default function parseComponent (vueComponentOptions) { componentOptions.deriveDataFromProps = createObserver() } else { componentOptions.didUpdate = createObserver(true) - } - - if (Array.isArray(vueOptions.wxsCallMethods)) { - vueOptions.wxsCallMethods.forEach(callMethod => { - componentOptions.methods[callMethod] = function (args) { - return this.$vm[callMethod](args) - } - }) + } + + if (Array.isArray(vueOptions.wxsCallMethods)) { + vueOptions.wxsCallMethods.forEach(callMethod => { + componentOptions.methods[callMethod] = function (args) { + return this.$vm[callMethod](args) + } + }) } return componentOptions -} +} diff --git a/src/platforms/mp-alipay/runtime/wrapper/page-parser.js b/src/platforms/mp-alipay/runtime/wrapper/page-parser.js index 500bdff6e11b50366bc8aa1afaa37d9d3ff39365..756a6534f70efff0de49b47d20ccf4bf3ddbd910 100644 --- a/src/platforms/mp-alipay/runtime/wrapper/page-parser.js +++ b/src/platforms/mp-alipay/runtime/wrapper/page-parser.js @@ -16,6 +16,7 @@ import { import { handleRef, handleLink, + handleWrap, initBehavior, triggerEvent, initChildVues, @@ -87,6 +88,7 @@ export default function parsePage (vuePageOptions) { __r: handleRef, __e: handleEvent, __l: handleLink, + __w: handleWrap, triggerEvent } diff --git a/src/platforms/mp-alipay/runtime/wrapper/util.js b/src/platforms/mp-alipay/runtime/wrapper/util.js index 01e9a52f6cd44c3496540f0a6ef091b5c42b30ca..bfa4757f4005da5b8a32019fade8f993ef503e4a 100644 --- a/src/platforms/mp-alipay/runtime/wrapper/util.js +++ b/src/platforms/mp-alipay/runtime/wrapper/util.js @@ -115,11 +115,12 @@ export function handleRef (ref) { if (ref.props['data-com-type'] === 'wx') { const eventProps = {} let refProps = ref.props + const eventList = refProps['data-event-list'].split(',') // 初始化支付宝小程序组件事件 Object.keys(refProps).forEach(key => { - const handler = refProps[key] - const res = key.match(/^on([A-Z])(\S*)/) - if (res && typeof handler === 'function' && handler.name === 'bound handleEvent') { + if (eventList.includes(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) @@ -219,3 +220,19 @@ export const handleLink = (function () { (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 { + // TODO remove handleRef + this[key] = function () { + mp.props[eventName].apply(this, arguments) + } + } + }) +}