diff --git a/packages/uni-template-compiler/__tests__/compiler.spec.js b/packages/uni-template-compiler/__tests__/compiler.spec.js index ffe3352f7d72ec8869e989478761069a83a46887..dc9dc5aac9a0cefdefd7ff1bd323ec648055e9a1 100644 --- a/packages/uni-template-compiler/__tests__/compiler.spec.js +++ b/packages/uni-template-compiler/__tests__/compiler.spec.js @@ -326,6 +326,12 @@ describe('mp:compiler', () => { '', '' ) + // v-for + assertCodegen( + 'test', + 'test', + 'with(this){if(!_isMounted){e0=function($event,item){var _temp=arguments[arguments.length-1].currentTarget.dataset,_temp2=(_temp.eventParams||_temp["event-params"])[0],item=_temp2.item;var _temp,_temp2;return $test.test(item)}}}' + ) // tricky symbols in args // assertCodegen( // ``, diff --git a/packages/uni-template-compiler/lib/constants.js b/packages/uni-template-compiler/lib/constants.js index 4597c3a33f28c5ab1454155ed8269e6b553e89b7..885ee953b3049c402e397edd5e3798a1564fa313 100644 --- a/packages/uni-template-compiler/lib/constants.js +++ b/packages/uni-template-compiler/lib/constants.js @@ -62,6 +62,7 @@ module.exports = { VAR_FILTER: 'F', ATTR_DATA_EVENT_OPTS: 'data-event-opts', ATTR_DATA_COM_TYPE: 'data-com-type', + ATTR_DATA_EVENT_PARAMS: 'data-event-params', INTERNAL_GET_ORIG, INTERNAL_GET_CLASS, INTERNAL_GET_STYLE, @@ -120,4 +121,4 @@ module.exports = { IDENTIFIER_STYLE: '__$$style$$__', IDENTIFIER_EVENT: '__$$event$$__', IDENTIFIER_GLOBAL: '__$$global$$__' -} +} diff --git a/packages/uni-template-compiler/lib/script/traverse/data/event.js b/packages/uni-template-compiler/lib/script/traverse/data/event.js index c1dccb98a83d8847ea38ad9d033dca8a95953264..bbb42c8b2674a9c08954f1eff12e4dbe9888b4e3 100644 --- a/packages/uni-template-compiler/lib/script/traverse/data/event.js +++ b/packages/uni-template-compiler/lib/script/traverse/data/event.js @@ -1,10 +1,12 @@ const t = require('@babel/types') +const parser = require('@babel/parser') const { IDENTIFIER_EVENT, VUE_EVENT_MODIFIERS, INTERNAL_EVENT_PROXY, ATTR_DATA_EVENT_OPTS, + ATTR_DATA_EVENT_PARAMS, INTERNAL_SET_SYNC } = require('../../../constants') @@ -212,8 +214,9 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, let isOnce = false const methods = [] + const params = [] - if (type) { + if (type) { isPassive = type.charAt(0) === VUE_EVENT_MODIFIERS.passive type = isPassive ? type.slice(1) : type @@ -318,7 +321,7 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, ReturnStatement (path) { const argument = path.node.argument if (t.isCallExpression(argument)) { - if (t.isIdentifier(argument.callee)) { + if (t.isIdentifier(argument.callee)) { // || t.isMemberExpression(argument.callee) anonymous = false parseEventByCallExpression(argument, methods) } @@ -326,6 +329,27 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, } }) if (anonymous) { + // 处理复杂表达式中使用的局部变量(主要在v-for中定义) + funcPath.traverse({ + Identifier (path) { + const scope = path.scope + const node = path.node + const name = node.name + if (path.key !== 'key' && path.key !== 'property' && scope && !scope.hasOwnBinding(name) && scope.hasBinding(name)) { + params.push(name) + } + } + }) + params.forEach(name => { + funcPath.node.params.push(t.identifier(name)) + }) + if (params.length) { + const datasetUid = funcPath.scope.generateDeclaredUidIdentifier().name + const paramsUid = funcPath.scope.generateDeclaredUidIdentifier().name + const dataset = ATTR_DATA_EVENT_PARAMS.substring(5) + const code = `var ${datasetUid}=arguments[arguments.length-1].currentTarget.dataset,${paramsUid}=(${datasetUid}.${dataset.replace(/-([a-z])/, (_, str) => str.toUpperCase())}||${datasetUid}['${dataset}'])[0],${params.map(item => `${item}=${paramsUid}.${item}`).join(',')}` + funcPath.node.body.body.unshift(parser.parse(code).program.body[0]) + } methods.push(addEventExpressionStatement(funcPath, state, isComponent, isNativeOn)) } } @@ -334,6 +358,7 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, return { type, + params, methods, modifiers: { isCatch, @@ -358,6 +383,7 @@ function _processEvent (path, state, isComponent, isNativeOn = false, tagName, r const valuePath = propertyPath.get('value') const { type, + params, methods, modifiers: { isCatch, @@ -393,12 +419,13 @@ function _processEvent (path, state, isComponent, isNativeOn = false, tagName, r if (isCustom) { optType = VUE_EVENT_MODIFIERS.custom + optType } - opts.push( - t.arrayExpression([ + opts.push({ + opt: t.arrayExpression([ t.stringLiteral(optType), t.arrayExpression(methods) - ]) - ) + ]), + params + }) keyPath.replaceWith( t.stringLiteral( @@ -422,15 +449,18 @@ module.exports = function processEvent (paths, path, state, isComponent, tagName const ret = [] const opts = [] + const params = [] if (onPath) { - _processEvent(onPath, state, isComponent, false, tagName, ret).forEach(opt => { + _processEvent(onPath, state, isComponent, false, tagName, ret).forEach(({ opt, params: array }) => { opts.push(opt) + params.push(...array) }) } if (nativeOnPath) { - _processEvent(nativeOnPath, state, isComponent, true, tagName, ret).forEach(opt => { + _processEvent(nativeOnPath, state, isComponent, true, tagName, ret).forEach(({ opt, params: array }) => { opts.push(opt) + params.push(...array) }) } if (!opts.length) { @@ -444,5 +474,15 @@ module.exports = function processEvent (paths, path, state, isComponent, tagName ) ) + if (params.length) { + ret.push( + t.objectProperty( + t.stringLiteral(ATTR_DATA_EVENT_PARAMS), + // 使用数组格式,直接使用对象格式微信小程序编译会报错 + t.stringLiteral(`{{[{${params.join(',')}}]}}`) + ) + ) + } + return ret } diff --git a/packages/uni-template-compiler/lib/script/traverse/visitor.js b/packages/uni-template-compiler/lib/script/traverse/visitor.js index 5a81060f39a7e20260f23a87d92fa04569d17cff..6f41068ccc289be09072a2c27e4ed880c5f51c8f 100644 --- a/packages/uni-template-compiler/lib/script/traverse/visitor.js +++ b/packages/uni-template-compiler/lib/script/traverse/visitor.js @@ -132,7 +132,7 @@ function checkUsingGlobalComponents (name, globalUsingComponents, state) { } module.exports = { - noScope: true, + noScope: false, MemberExpression (path) { if ( // t.m(123) t.isIdentifier(path.node.object) && diff --git a/src/core/runtime/wrapper/util.js b/src/core/runtime/wrapper/util.js index be9f757528e5bbc21e566d0eeae91a5cc0eebf00..f826a183effbf7f83315ffb1817a50bf095b52e5 100644 --- a/src/core/runtime/wrapper/util.js +++ b/src/core/runtime/wrapper/util.js @@ -542,14 +542,17 @@ export function handleEvent (event) { } handler.once = true } - ret.push(handler.apply(handlerCtx, processEventArgs( + const params = processEventArgs( this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName - ))) + ) || [] + // 参数尾部增加原始事件对象用于复杂表达式内获取额外数据 + // eslint-disable-next-line no-sparse-arrays + ret.push(handler.apply(handlerCtx, params.concat([, , , , , , , , , , event]))) } }) }