Skip to content

Commit b359aa9

Browse files
committed
fix(language-core): allow binding multiple events with the same name
close #4369
1 parent dacbfdf commit b359aa9

File tree

2 files changed

+34
-48
lines changed

2 files changed

+34
-48
lines changed

packages/language-core/lib/codegen/template/elementProps.ts

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { camelize } from '@vue/shared';
33
import { minimatch } from 'minimatch';
44
import type { Code, VueCodeInformation, VueCompilerOptions } from '../../types';
55
import { hyphenateAttr, hyphenateTag } from '../../utils/shared';
6-
import { conditionWrapWith, newLine, variableNameRegex, wrapWith } from '../common';
6+
import { conditionWrapWith, variableNameRegex, wrapWith } from '../common';
77
import { generateCamelized } from './camelized';
88
import type { TemplateCodegenContext } from './context';
99
import type { TemplateCodegenOptions } from './index';
@@ -20,23 +20,9 @@ export function* generateElementProps(
2020
enableCodeFeatures: boolean,
2121
propsFailedExps?: CompilerDOM.SimpleExpressionNode[],
2222
): Generator<Code> {
23-
let styleAttrNum = 0;
24-
let classAttrNum = 0;
25-
2623
const isIntrinsicElement = node.tagType === CompilerDOM.ElementTypes.ELEMENT || node.tagType === CompilerDOM.ElementTypes.TEMPLATE;
2724
const canCamelize = node.tagType === CompilerDOM.ElementTypes.COMPONENT;
2825

29-
if (props.some(prop =>
30-
prop.type === CompilerDOM.NodeTypes.DIRECTIVE
31-
&& prop.name === 'bind'
32-
&& !prop.arg
33-
&& prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
34-
)) {
35-
// fix https://github.com/vuejs/language-tools/issues/2166
36-
styleAttrNum++;
37-
classAttrNum++;
38-
}
39-
4026
if (isIntrinsicElement) {
4127
for (const prop of props) {
4228
if (
@@ -46,10 +32,11 @@ export function* generateElementProps(
4632
&& !prop.arg.loc.source.startsWith('[')
4733
&& !prop.arg.loc.source.endsWith(']')
4834
) {
35+
yield `...{ `;
4936
yield* generateEventArg(ctx, prop.arg, true);
5037
yield `: `;
5138
yield* generateEventExpression(options, ctx, prop);
52-
yield `,${newLine}`;
39+
yield `}, `;
5340
}
5441
else if (
5542
prop.type === CompilerDOM.NodeTypes.DIRECTIVE
@@ -69,26 +56,17 @@ export function* generateElementProps(
6956
}
7057
}
7158
else {
72-
let generatedEvent = false;
7359
for (const prop of props) {
7460
if (
7561
prop.type === CompilerDOM.NodeTypes.DIRECTIVE
7662
&& prop.name === 'on'
7763
&& prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
64+
&& !prop.arg.loc.source.startsWith('[')
65+
&& !prop.arg.loc.source.endsWith(']')
7866
) {
79-
if (prop.arg.loc.source.startsWith('[') && prop.arg.loc.source.endsWith(']')) {
80-
continue;
81-
}
82-
if (!generatedEvent) {
83-
yield `...{ `;
84-
generatedEvent = true;
85-
}
86-
yield `'${camelize('on-' + prop.arg.loc.source)}': {} as any, `;
67+
yield `...{ '${camelize('on-' + prop.arg.loc.source)}': {} as any }, `;
8768
}
8869
}
89-
if (generatedEvent) {
90-
yield `}, `;
91-
}
9270
}
9371

9472
for (const prop of props) {
@@ -105,28 +83,29 @@ export function* generateElementProps(
10583
: prop.arg.loc.source
10684
: getModelValuePropName(node, options.vueCompilerOptions.target, options.vueCompilerOptions);
10785

108-
if (prop.modifiers.some(m => m === 'prop' || m === 'attr')) {
109-
propName = propName?.substring(1);
110-
}
111-
11286
if (
11387
propName === undefined
114-
|| options.vueCompilerOptions.dataAttributes.some(pattern => minimatch(propName, pattern))
115-
|| (propName === 'style' && ++styleAttrNum >= 2)
116-
|| (propName === 'class' && ++classAttrNum >= 2)
117-
|| (propName === 'name' && node.tagType === CompilerDOM.ElementTypes.SLOT) // #2308
88+
|| options.vueCompilerOptions.dataAttributes.some(pattern => minimatch(propName!, pattern))
11889
) {
11990
if (prop.exp && prop.exp.constType !== CompilerDOM.ConstantTypes.CAN_STRINGIFY) {
12091
propsFailedExps?.push(prop.exp);
12192
}
12293
continue;
12394
}
12495

96+
if (prop.modifiers.some(m => m === 'prop' || m === 'attr')) {
97+
propName = propName.substring(1);
98+
}
99+
100+
const shouldSpread = propName === 'style' || propName === 'class';
125101
const shouldCamelize = canCamelize
126102
&& (!prop.arg || (prop.arg.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && prop.arg.isStatic)) // isStatic
127103
&& hyphenateAttr(propName) === propName
128104
&& !options.vueCompilerOptions.htmlAttributes.some(pattern => minimatch(propName, pattern));
129105

106+
if (shouldSpread) {
107+
yield `...{ `;
108+
}
130109
const codes = wrapWith(
131110
prop.loc.start.offset,
132111
prop.loc.end.offset,
@@ -169,31 +148,32 @@ export function* generateElementProps(
169148
else {
170149
yield* codes;
171150
}
151+
if (shouldSpread) {
152+
yield ` }`;
153+
}
172154
yield `, `;
173155
}
174156
else if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE) {
175157
if (
176158
options.vueCompilerOptions.dataAttributes.some(pattern => minimatch(prop.name, pattern))
177-
|| (prop.name === 'style' && ++styleAttrNum >= 2)
178-
|| (prop.name === 'class' && ++classAttrNum >= 2)
179-
|| (prop.name === 'name' && node.tagType === CompilerDOM.ElementTypes.SLOT) // #2308
180-
) {
181-
continue;
182-
}
183-
184-
if (
185-
options.vueCompilerOptions.target < 3
186-
&& prop.name === 'persisted'
187-
&& node.tag.toLowerCase() === 'transition'
188-
) {
189159
// Vue 2 Transition doesn't support "persisted" property but `@vue/compiler-dom always adds it (#3881)
160+
|| (
161+
options.vueCompilerOptions.target < 3
162+
&& prop.name === 'persisted'
163+
&& node.tag.toLowerCase() === 'transition'
164+
)
165+
) {
190166
continue;
191167
}
192168

169+
const shouldSpread = prop.name === 'style' || prop.name === 'class';
193170
const shouldCamelize = canCamelize
194171
&& hyphenateAttr(prop.name) === prop.name
195172
&& !options.vueCompilerOptions.htmlAttributes.some(pattern => minimatch(prop.name, pattern));
196173

174+
if (shouldSpread) {
175+
yield `...{ `;
176+
}
197177
const codes = conditionWrapWith(
198178
enableCodeFeatures,
199179
prop.loc.start.offset,
@@ -232,6 +212,9 @@ export function* generateElementProps(
232212
else {
233213
yield* codes;
234214
}
215+
if (shouldSpread) {
216+
yield ` }`;
217+
}
235218
yield `, `;
236219
}
237220
else if (
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
<div @keyup.enter="() => { }" @keyup.space.prevent="() => { }" />
3+
</template>

0 commit comments

Comments
 (0)