mirror of https://github.com/vuejs/core.git
feat: support v-on="obj" (#149)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
parent
421eba3e01
commit
9412c20531
|
@ -75,3 +75,14 @@ export function render(_ctx) {
|
||||||
return n0
|
return n0
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: element transform > v-on="obj" 1`] = `
|
||||||
|
"import { renderEffect as _renderEffect, setDynamicEvents as _setDynamicEvents, template as _template } from 'vue/vapor';
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const n0 = t0()
|
||||||
|
_renderEffect(() => _setDynamicEvents(n0, _ctx.obj))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
|
@ -344,4 +344,32 @@ describe('compiler: element transform', () => {
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('v-on="obj"', () => {
|
||||||
|
const { code, ir } = compileWithElementTransform(`<div v-on="obj" />`)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(ir.block.effect).toMatchObject([
|
||||||
|
{
|
||||||
|
expressions: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'obj',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_DYNAMIC_EVENTS,
|
||||||
|
element: 0,
|
||||||
|
event: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'obj',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
expect(code).contains('_setDynamicEvents(n0, _ctx.obj)')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { fnExpRE, isMemberExpression } from '@vue/compiler-dom'
|
import { fnExpRE, isMemberExpression } from '@vue/compiler-dom'
|
||||||
import type { CodegenContext } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import type { SetEventIRNode } from '../ir'
|
import type { SetDynamicEventsIRNode, SetEventIRNode } from '../ir'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
import {
|
import {
|
||||||
type CodeFragment,
|
type CodeFragment,
|
||||||
|
@ -93,6 +93,21 @@ export function genSetEvent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function genSetDynamicEvents(
|
||||||
|
oper: SetDynamicEventsIRNode,
|
||||||
|
context: CodegenContext,
|
||||||
|
): CodeFragment[] {
|
||||||
|
const { vaporHelper } = context
|
||||||
|
return [
|
||||||
|
NEWLINE,
|
||||||
|
...genCall(
|
||||||
|
vaporHelper('setDynamicEvents'),
|
||||||
|
`n${oper.element}`,
|
||||||
|
genExpression(oper.event, context),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
function genArrayExpression(elements: string[]) {
|
function genArrayExpression(elements: string[]) {
|
||||||
return `[${elements.map(it => JSON.stringify(it)).join(', ')}]`
|
return `[${elements.map(it => JSON.stringify(it)).join(', ')}]`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { type IREffect, IRNodeTypes, type OperationNode } from '../ir'
|
import { type IREffect, IRNodeTypes, type OperationNode } from '../ir'
|
||||||
import type { CodegenContext } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import { genInsertNode, genPrependNode } from './dom'
|
import { genInsertNode, genPrependNode } from './dom'
|
||||||
import { genSetEvent } from './event'
|
import { genSetDynamicEvents, genSetEvent } from './event'
|
||||||
import { genFor } from './for'
|
import { genFor } from './for'
|
||||||
import { genSetHtml } from './html'
|
import { genSetHtml } from './html'
|
||||||
import { genIf } from './if'
|
import { genIf } from './if'
|
||||||
|
@ -38,6 +38,8 @@ export function genOperation(
|
||||||
return genSetText(oper, context)
|
return genSetText(oper, context)
|
||||||
case IRNodeTypes.SET_EVENT:
|
case IRNodeTypes.SET_EVENT:
|
||||||
return genSetEvent(oper, context)
|
return genSetEvent(oper, context)
|
||||||
|
case IRNodeTypes.SET_DYNAMIC_EVENTS:
|
||||||
|
return genSetDynamicEvents(oper, context)
|
||||||
case IRNodeTypes.SET_HTML:
|
case IRNodeTypes.SET_HTML:
|
||||||
return genSetHtml(oper, context)
|
return genSetHtml(oper, context)
|
||||||
case IRNodeTypes.SET_REF:
|
case IRNodeTypes.SET_REF:
|
||||||
|
|
|
@ -21,6 +21,7 @@ export enum IRNodeTypes {
|
||||||
SET_DYNAMIC_PROPS,
|
SET_DYNAMIC_PROPS,
|
||||||
SET_TEXT,
|
SET_TEXT,
|
||||||
SET_EVENT,
|
SET_EVENT,
|
||||||
|
SET_DYNAMIC_EVENTS,
|
||||||
SET_HTML,
|
SET_HTML,
|
||||||
SET_REF,
|
SET_REF,
|
||||||
SET_MODEL_VALUE,
|
SET_MODEL_VALUE,
|
||||||
|
@ -94,6 +95,12 @@ export interface SetDynamicPropsIRNode extends BaseIRNode {
|
||||||
props: IRProps[]
|
props: IRProps[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetDynamicEventsIRNode extends BaseIRNode {
|
||||||
|
type: IRNodeTypes.SET_DYNAMIC_EVENTS
|
||||||
|
element: number
|
||||||
|
event: SimpleExpressionNode
|
||||||
|
}
|
||||||
|
|
||||||
export interface SetTextIRNode extends BaseIRNode {
|
export interface SetTextIRNode extends BaseIRNode {
|
||||||
type: IRNodeTypes.SET_TEXT
|
type: IRNodeTypes.SET_TEXT
|
||||||
element: number
|
element: number
|
||||||
|
@ -172,6 +179,7 @@ export type OperationNode =
|
||||||
| SetDynamicPropsIRNode
|
| SetDynamicPropsIRNode
|
||||||
| SetTextIRNode
|
| SetTextIRNode
|
||||||
| SetEventIRNode
|
| SetEventIRNode
|
||||||
|
| SetDynamicEventsIRNode
|
||||||
| SetHtmlIRNode
|
| SetHtmlIRNode
|
||||||
| SetRefIRNode
|
| SetRefIRNode
|
||||||
| SetModelValueIRNode
|
| SetModelValueIRNode
|
||||||
|
|
|
@ -14,14 +14,26 @@ const delegatedEvents = /*#__PURE__*/ makeMap(
|
||||||
|
|
||||||
export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
let { arg, exp, loc, modifiers } = dir
|
let { arg, exp, loc, modifiers } = dir
|
||||||
if (!exp && !modifiers.length) {
|
if (!exp && (!modifiers.length || !arg)) {
|
||||||
context.options.onError(
|
context.options.onError(
|
||||||
createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc),
|
createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
// TODO support v-on="{}"
|
// v-on="obj"
|
||||||
|
if (exp) {
|
||||||
|
context.registerEffect(
|
||||||
|
[exp],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_DYNAMIC_EVENTS,
|
||||||
|
element: context.reference(),
|
||||||
|
event: exp,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,3 +122,12 @@ const delegatedEventHandler = (e: Event) => {
|
||||||
: node.parentNode
|
: node.parentNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setDynamicEvents(
|
||||||
|
el: HTMLElement,
|
||||||
|
events: Record<string, (...args: any[]) => any>,
|
||||||
|
) {
|
||||||
|
for (const [event, eventHandler] of Object.entries(events)) {
|
||||||
|
on(el, event, () => eventHandler, { effect: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ export {
|
||||||
setDynamicProp,
|
setDynamicProp,
|
||||||
setDynamicProps,
|
setDynamicProps,
|
||||||
} from './dom/prop'
|
} from './dom/prop'
|
||||||
export { on, delegate, delegateEvents } from './dom/event'
|
export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
|
||||||
export { setRef } from './dom/templateRef'
|
export { setRef } from './dom/templateRef'
|
||||||
|
|
||||||
export { defineComponent } from './apiDefineComponent'
|
export { defineComponent } from './apiDefineComponent'
|
||||||
|
|
Loading…
Reference in New Issue