mirror of https://github.com/vuejs/core.git
fix(compiler-vapor): v-on for component support `$event` argument (#177)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
parent
9e0cd20da0
commit
e640ec6088
|
@ -91,6 +91,17 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: element transform > component > should wrap as function if v-on expression is inline statement 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const n0 = _createComponent(_resolveComponent("Foo"), [{
|
||||||
|
onBar: () => $event => (_ctx.handleBar($event))
|
||||||
|
}], true)
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: element transform > component > static props 1`] = `
|
exports[`compiler: element transform > component > static props 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
|
"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
|
||||||
|
|
||||||
|
|
|
@ -364,6 +364,29 @@ describe('compiler: element transform', () => {
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should wrap as function if v-on expression is inline statement', () => {
|
||||||
|
const { code, ir } = compileWithElementTransform(
|
||||||
|
`<Foo v-on:bar="handleBar($event)" />`,
|
||||||
|
)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(code).contains(`onBar: () => $event => (_ctx.handleBar($event))`)
|
||||||
|
expect(ir.block.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||||
|
tag: 'Foo',
|
||||||
|
props: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
key: { content: 'bar' },
|
||||||
|
handler: true,
|
||||||
|
values: [{ content: 'handleBar($event)' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('static props', () => {
|
test('static props', () => {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
import { genPropKey } from './prop'
|
import { genPropKey } from './prop'
|
||||||
import { createSimpleExpression } from '@vue/compiler-dom'
|
import { createSimpleExpression } from '@vue/compiler-dom'
|
||||||
|
import { genEventHandler } from './event'
|
||||||
|
|
||||||
// TODO: generate component slots
|
// TODO: generate component slots
|
||||||
export function genCreateComponent(
|
export function genCreateComponent(
|
||||||
|
@ -74,9 +75,10 @@ export function genCreateComponent(
|
||||||
...props.map(prop => {
|
...props.map(prop => {
|
||||||
return [
|
return [
|
||||||
...genPropKey(prop, context),
|
...genPropKey(prop, context),
|
||||||
': () => (',
|
': ',
|
||||||
...genExpression(prop.values[0], context),
|
...(prop.handler
|
||||||
')',
|
? genEventHandler(context, prop.values[0])
|
||||||
|
: ['() => (', ...genExpression(prop.values[0], context), ')']),
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
import { fnExpRE, isMemberExpression } from '@vue/compiler-dom'
|
import {
|
||||||
|
type SimpleExpressionNode,
|
||||||
|
fnExpRE,
|
||||||
|
isMemberExpression,
|
||||||
|
} from '@vue/compiler-dom'
|
||||||
import type { CodegenContext } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import type { SetDynamicEventsIRNode, SetEventIRNode } from '../ir'
|
import type { SetDynamicEventsIRNode, SetEventIRNode } from '../ir'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
|
@ -15,11 +19,11 @@ export function genSetEvent(
|
||||||
oper: SetEventIRNode,
|
oper: SetEventIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { vaporHelper, options } = context
|
const { vaporHelper } = context
|
||||||
const { element, key, keyOverride, value, modifiers, delegate, effect } = oper
|
const { element, key, keyOverride, value, modifiers, delegate, effect } = oper
|
||||||
|
|
||||||
const name = genName()
|
const name = genName()
|
||||||
const handler = genEventHandler()
|
const handler = genEventHandler(context, value)
|
||||||
const eventOptions = genEventOptions()
|
const eventOptions = genEventOptions()
|
||||||
|
|
||||||
if (delegate) {
|
if (delegate) {
|
||||||
|
@ -51,30 +55,6 @@ export function genSetEvent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function genEventHandler() {
|
|
||||||
if (value && value.content.trim()) {
|
|
||||||
const isMemberExp = isMemberExpression(value.content, options)
|
|
||||||
const isInlineStatement = !(isMemberExp || fnExpRE.test(value.content))
|
|
||||||
|
|
||||||
if (isInlineStatement) {
|
|
||||||
const expr = context.withId(() => genExpression(value, context), {
|
|
||||||
$event: null,
|
|
||||||
})
|
|
||||||
const hasMultipleStatements = value.content.includes(`;`)
|
|
||||||
return [
|
|
||||||
'() => $event => ',
|
|
||||||
hasMultipleStatements ? '{' : '(',
|
|
||||||
...expr,
|
|
||||||
hasMultipleStatements ? '}' : ')',
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
return ['() => ', ...genExpression(value, context)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['() => {}']
|
|
||||||
}
|
|
||||||
|
|
||||||
function genEventOptions(): CodeFragment[] | undefined {
|
function genEventOptions(): CodeFragment[] | undefined {
|
||||||
let { options, keys, nonKeys } = modifiers
|
let { options, keys, nonKeys } = modifiers
|
||||||
if (!options.length && !nonKeys.length && !keys.length && !effect) return
|
if (!options.length && !nonKeys.length && !keys.length && !effect) return
|
||||||
|
@ -111,3 +91,30 @@ export function genSetDynamicEvents(
|
||||||
function genArrayExpression(elements: string[]) {
|
function genArrayExpression(elements: string[]) {
|
||||||
return `[${elements.map(it => JSON.stringify(it)).join(', ')}]`
|
return `[${elements.map(it => JSON.stringify(it)).join(', ')}]`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function genEventHandler(
|
||||||
|
context: CodegenContext,
|
||||||
|
value: SimpleExpressionNode | undefined,
|
||||||
|
) {
|
||||||
|
if (value && value.content.trim()) {
|
||||||
|
const isMemberExp = isMemberExpression(value.content, context.options)
|
||||||
|
const isInlineStatement = !(isMemberExp || fnExpRE.test(value.content))
|
||||||
|
|
||||||
|
if (isInlineStatement) {
|
||||||
|
const expr = context.withId(() => genExpression(value, context), {
|
||||||
|
$event: null,
|
||||||
|
})
|
||||||
|
const hasMultipleStatements = value.content.includes(`;`)
|
||||||
|
return [
|
||||||
|
'() => $event => ',
|
||||||
|
hasMultipleStatements ? '{' : '(',
|
||||||
|
...expr,
|
||||||
|
hasMultipleStatements ? '}' : ')',
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
return ['() => ', ...genExpression(value, context)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['() => {}']
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
|
import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
|
||||||
|
import { toHandlerKey } from '@vue/shared'
|
||||||
|
|
||||||
// only the static key prop will reach here
|
// only the static key prop will reach here
|
||||||
export function genSetProp(
|
export function genSetProp(
|
||||||
|
@ -86,7 +87,7 @@ function genLiteralObjectProps(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function genPropKey(
|
export function genPropKey(
|
||||||
{ key: node, modifier, runtimeCamelize, runtimeHandler }: IRProp,
|
{ key: node, modifier, runtimeCamelize, handler }: IRProp,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { helper } = context
|
const { helper } = context
|
||||||
|
@ -94,7 +95,7 @@ export function genPropKey(
|
||||||
// static arg was transformed by v-bind transformer
|
// static arg was transformed by v-bind transformer
|
||||||
if (node.isStatic) {
|
if (node.isStatic) {
|
||||||
// only quote keys if necessary
|
// only quote keys if necessary
|
||||||
const keyName = node.content
|
const keyName = handler ? toHandlerKey(node.content) : node.content
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
isSimpleIdentifier(keyName) ? keyName : JSON.stringify(keyName),
|
isSimpleIdentifier(keyName) ? keyName : JSON.stringify(keyName),
|
||||||
|
@ -108,7 +109,7 @@ export function genPropKey(
|
||||||
if (runtimeCamelize) {
|
if (runtimeCamelize) {
|
||||||
key = genCall(helper('camelize'), key)
|
key = genCall(helper('camelize'), key)
|
||||||
}
|
}
|
||||||
if (runtimeHandler) {
|
if (handler) {
|
||||||
key = genCall(helper('toHandlerKey'), key)
|
key = genCall(helper('toHandlerKey'), key)
|
||||||
}
|
}
|
||||||
return ['[', modifier && `${JSON.stringify(modifier)} + `, ...key, ']']
|
return ['[', modifier && `${JSON.stringify(modifier)} + `, ...key, ']']
|
||||||
|
|
|
@ -43,7 +43,7 @@ export interface DirectiveTransformResult {
|
||||||
value: SimpleExpressionNode
|
value: SimpleExpressionNode
|
||||||
modifier?: '.' | '^'
|
modifier?: '.' | '^'
|
||||||
runtimeCamelize?: boolean
|
runtimeCamelize?: boolean
|
||||||
runtimeHandler?: boolean
|
handler?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// A structural directive transform is technically also a NodeTransform;
|
// A structural directive transform is technically also a NodeTransform;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
import type { DirectiveTransform } from '../transform'
|
import type { DirectiveTransform } from '../transform'
|
||||||
import { IRNodeTypes, type KeyOverride, type SetEventIRNode } from '../ir'
|
import { IRNodeTypes, type KeyOverride, type SetEventIRNode } from '../ir'
|
||||||
import { resolveModifiers } from '@vue/compiler-dom'
|
import { resolveModifiers } from '@vue/compiler-dom'
|
||||||
import { extend, makeMap, toHandlerKey } from '@vue/shared'
|
import { extend, makeMap } from '@vue/shared'
|
||||||
import { resolveExpression } from '../utils'
|
import { resolveExpression } from '../utils'
|
||||||
import { EMPTY_EXPRESSION } from './utils'
|
import { EMPTY_EXPRESSION } from './utils'
|
||||||
|
|
||||||
|
@ -61,14 +61,11 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isComponent) {
|
if (isComponent) {
|
||||||
if (arg.isStatic) {
|
|
||||||
arg = extend({}, arg, { content: toHandlerKey(arg.content) })
|
|
||||||
}
|
|
||||||
const handler = exp || EMPTY_EXPRESSION
|
const handler = exp || EMPTY_EXPRESSION
|
||||||
return {
|
return {
|
||||||
key: arg,
|
key: arg,
|
||||||
value: handler,
|
value: handler,
|
||||||
runtimeHandler: !arg.isStatic,
|
handler: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue