提交 96443dee 编写于 作者: Q qiang

fix: 解决v-for中方法使用复杂表达式报错的问题 fixed #373

上级 68cd6c67
...@@ -326,6 +326,12 @@ describe('mp:compiler', () => { ...@@ -326,6 +326,12 @@ describe('mp:compiler', () => {
'<input @input="onInput($event, 2+2);">', '<input @input="onInput($event, 2+2);">',
'<input data-event-opts="{{[[\'input\',[[\'onInput\',[\'$event\',2+2]]]]]}}" bindinput="__e"/>' '<input data-event-opts="{{[[\'input\',[[\'onInput\',[\'$event\',2+2]]]]]}}" bindinput="__e"/>'
) )
// v-for
assertCodegen(
'<view v-for="(item,index) in list" :key="index"><view @click="$test.test(item)">test</view></view>',
'<block wx:for="{{list}}" wx:for-item="item" wx:for-index="index" wx:key="index"><view><view data-event-opts="{{[[\'tap\',[[\'e0\',[\'$event\']]]]]}}" data-event-params="{{[{item}]}}" bindtap="__e">test</view></view></block>',
'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 // tricky symbols in args
// assertCodegen( // assertCodegen(
// `<input @input="onInput(');[\\'());');">`, // `<input @input="onInput(');[\\'());');">`,
......
...@@ -62,6 +62,7 @@ module.exports = { ...@@ -62,6 +62,7 @@ module.exports = {
VAR_FILTER: 'F', VAR_FILTER: 'F',
ATTR_DATA_EVENT_OPTS: 'data-event-opts', ATTR_DATA_EVENT_OPTS: 'data-event-opts',
ATTR_DATA_COM_TYPE: 'data-com-type', ATTR_DATA_COM_TYPE: 'data-com-type',
ATTR_DATA_EVENT_PARAMS: 'data-event-params',
INTERNAL_GET_ORIG, INTERNAL_GET_ORIG,
INTERNAL_GET_CLASS, INTERNAL_GET_CLASS,
INTERNAL_GET_STYLE, INTERNAL_GET_STYLE,
...@@ -120,4 +121,4 @@ module.exports = { ...@@ -120,4 +121,4 @@ module.exports = {
IDENTIFIER_STYLE: '__$$style$$__', IDENTIFIER_STYLE: '__$$style$$__',
IDENTIFIER_EVENT: '__$$event$$__', IDENTIFIER_EVENT: '__$$event$$__',
IDENTIFIER_GLOBAL: '__$$global$$__' IDENTIFIER_GLOBAL: '__$$global$$__'
} }
const t = require('@babel/types') const t = require('@babel/types')
const parser = require('@babel/parser')
const { const {
IDENTIFIER_EVENT, IDENTIFIER_EVENT,
VUE_EVENT_MODIFIERS, VUE_EVENT_MODIFIERS,
INTERNAL_EVENT_PROXY, INTERNAL_EVENT_PROXY,
ATTR_DATA_EVENT_OPTS, ATTR_DATA_EVENT_OPTS,
ATTR_DATA_EVENT_PARAMS,
INTERNAL_SET_SYNC INTERNAL_SET_SYNC
} = require('../../../constants') } = require('../../../constants')
...@@ -212,8 +214,9 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, ...@@ -212,8 +214,9 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false,
let isOnce = false let isOnce = false
const methods = [] const methods = []
const params = []
if (type) { if (type) {
isPassive = type.charAt(0) === VUE_EVENT_MODIFIERS.passive isPassive = type.charAt(0) === VUE_EVENT_MODIFIERS.passive
type = isPassive ? type.slice(1) : type type = isPassive ? type.slice(1) : type
...@@ -318,7 +321,7 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, ...@@ -318,7 +321,7 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false,
ReturnStatement (path) { ReturnStatement (path) {
const argument = path.node.argument const argument = path.node.argument
if (t.isCallExpression(argument)) { if (t.isCallExpression(argument)) {
if (t.isIdentifier(argument.callee)) { if (t.isIdentifier(argument.callee)) { // || t.isMemberExpression(argument.callee)
anonymous = false anonymous = false
parseEventByCallExpression(argument, methods) parseEventByCallExpression(argument, methods)
} }
...@@ -326,6 +329,27 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, ...@@ -326,6 +329,27 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false,
} }
}) })
if (anonymous) { 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)) methods.push(addEventExpressionStatement(funcPath, state, isComponent, isNativeOn))
} }
} }
...@@ -334,6 +358,7 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, ...@@ -334,6 +358,7 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false,
return { return {
type, type,
params,
methods, methods,
modifiers: { modifiers: {
isCatch, isCatch,
...@@ -358,6 +383,7 @@ function _processEvent (path, state, isComponent, isNativeOn = false, tagName, r ...@@ -358,6 +383,7 @@ function _processEvent (path, state, isComponent, isNativeOn = false, tagName, r
const valuePath = propertyPath.get('value') const valuePath = propertyPath.get('value')
const { const {
type, type,
params,
methods, methods,
modifiers: { modifiers: {
isCatch, isCatch,
...@@ -393,12 +419,13 @@ function _processEvent (path, state, isComponent, isNativeOn = false, tagName, r ...@@ -393,12 +419,13 @@ function _processEvent (path, state, isComponent, isNativeOn = false, tagName, r
if (isCustom) { if (isCustom) {
optType = VUE_EVENT_MODIFIERS.custom + optType optType = VUE_EVENT_MODIFIERS.custom + optType
} }
opts.push( opts.push({
t.arrayExpression([ opt: t.arrayExpression([
t.stringLiteral(optType), t.stringLiteral(optType),
t.arrayExpression(methods) t.arrayExpression(methods)
]) ]),
) params
})
keyPath.replaceWith( keyPath.replaceWith(
t.stringLiteral( t.stringLiteral(
...@@ -422,15 +449,18 @@ module.exports = function processEvent (paths, path, state, isComponent, tagName ...@@ -422,15 +449,18 @@ module.exports = function processEvent (paths, path, state, isComponent, tagName
const ret = [] const ret = []
const opts = [] const opts = []
const params = []
if (onPath) { 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) opts.push(opt)
params.push(...array)
}) })
} }
if (nativeOnPath) { 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) opts.push(opt)
params.push(...array)
}) })
} }
if (!opts.length) { if (!opts.length) {
...@@ -444,5 +474,15 @@ module.exports = function processEvent (paths, path, state, isComponent, tagName ...@@ -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 return ret
} }
...@@ -132,7 +132,7 @@ function checkUsingGlobalComponents (name, globalUsingComponents, state) { ...@@ -132,7 +132,7 @@ function checkUsingGlobalComponents (name, globalUsingComponents, state) {
} }
module.exports = { module.exports = {
noScope: true, noScope: false,
MemberExpression (path) { MemberExpression (path) {
if ( // t.m(123) if ( // t.m(123)
t.isIdentifier(path.node.object) && t.isIdentifier(path.node.object) &&
......
...@@ -542,14 +542,17 @@ export function handleEvent (event) { ...@@ -542,14 +542,17 @@ export function handleEvent (event) {
} }
handler.once = true handler.once = true
} }
ret.push(handler.apply(handlerCtx, processEventArgs( const params = processEventArgs(
this.$vm, this.$vm,
event, event,
eventArray[1], eventArray[1],
eventArray[2], eventArray[2],
isCustom, isCustom,
methodName methodName
))) ) || []
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
// eslint-disable-next-line no-sparse-arrays
ret.push(handler.apply(handlerCtx, params.concat([, , , , , , , , , , event])))
} }
}) })
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册