refactor: merge delegate & modifier options of event

This commit is contained in:
三咲智子 Kevin Deng 2024-02-25 15:11:25 +08:00
parent ff943f4ddf
commit fb3e8ee8c0
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
17 changed files with 362 additions and 266 deletions

View File

@ -146,13 +146,15 @@ export function render(_ctx) {
`;
exports[`compile > dynamic root nodes and interpolation 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<button></button>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.handleClick))
_on(n0, "click", () => _ctx.handleClick, {
delegate: true
})
_renderEffect(() => _setText(n0, _ctx.count, "foo", _ctx.count, "foo", _ctx.count))
_renderEffect(() => _setDynamicProp(n0, "id", _ctx.count))
return n0

View File

@ -1,14 +1,16 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler: v-for > basic v-for 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = _createFor(() => (_ctx.items), (_block) => {
const n2 = t0()
_recordMetadata(n2, "events", "click", _eventHandler(() => $event => (_ctx.remove(_block.s[0]))))
_on(n2, "click", () => $event => (_ctx.remove(_block.s[0])), {
delegate: true
})
const _updateEffect = () => {
const [item] = _block.s
_setText(n2, item)

View File

@ -1,13 +1,15 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`v-on > complex member expression w/ prefixIdentifiers: true 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.a['b' + _ctx.c]))
_on(n0, "click", () => _ctx.a['b' + _ctx.c], {
delegate: true
})
return n0
}"
`;
@ -46,7 +48,7 @@ export function render(_ctx) {
`;
exports[`v-on > event modifier 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<a></a>")
const t1 = _template("<form></form>")
const t2 = _template("<div></div>")
@ -76,249 +78,300 @@ export function render(_ctx) {
const n19 = t3()
const n20 = t3()
const n21 = t3()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["stop"]
}))
_on(n1, "submit", () => _ctx.handleEvent, undefined, {
_on(n0, "click", () => _ctx.handleEvent, {
modifiers: ["stop"],
delegate: true
})
_on(n1, "submit", () => _ctx.handleEvent, {
modifiers: ["prevent"]
})
_recordMetadata(n2, "events", "click", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["stop", "prevent"]
}))
_recordMetadata(n3, "events", "click", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["self"]
}))
_on(n4, "click", () => _ctx.handleEvent, { capture: true })
_on(n5, "click", () => _ctx.handleEvent, { once: true })
_on(n6, "scroll", () => _ctx.handleEvent, { passive: true })
_recordMetadata(n7, "events", "contextmenu", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["right"]
}))
_recordMetadata(n8, "events", "click", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["left"]
}))
_recordMetadata(n9, "events", "mouseup", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["middle"]
}))
_recordMetadata(n10, "events", "contextmenu", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["right"]
}))
_recordMetadata(n11, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["enter"]
}))
_recordMetadata(n12, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["tab"]
}))
_recordMetadata(n13, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["delete"]
}))
_recordMetadata(n14, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["esc"]
}))
_recordMetadata(n15, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["space"]
}))
_recordMetadata(n16, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["up"]
}))
_recordMetadata(n17, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["down"]
}))
_recordMetadata(n18, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
keys: ["left"]
}))
_recordMetadata(n19, "events", "keyup", _eventHandler(() => _ctx.submit, {
modifiers: ["middle"]
}))
_recordMetadata(n20, "events", "keyup", _eventHandler(() => _ctx.submit, {
modifiers: ["middle", "self"]
}))
_recordMetadata(n21, "events", "keyup", _eventHandler(() => _ctx.handleEvent, {
modifiers: ["self"],
keys: ["enter"]
}))
_on(n2, "click", () => _ctx.handleEvent, {
modifiers: ["stop", "prevent"],
delegate: true
})
_on(n3, "click", () => _ctx.handleEvent, {
modifiers: ["self"],
delegate: true
})
_on(n4, "click", () => _ctx.handleEvent, {
capture: true
})
_on(n5, "click", () => _ctx.handleEvent, {
once: true
})
_on(n6, "scroll", () => _ctx.handleEvent, {
passive: true
})
_on(n7, "contextmenu", () => _ctx.handleEvent, {
modifiers: ["right"],
delegate: true
})
_on(n8, "click", () => _ctx.handleEvent, {
modifiers: ["left"],
delegate: true
})
_on(n9, "mouseup", () => _ctx.handleEvent, {
modifiers: ["middle"],
delegate: true
})
_on(n10, "contextmenu", () => _ctx.handleEvent, {
modifiers: ["right"],
delegate: true
})
_on(n11, "keyup", () => _ctx.handleEvent, {
keys: ["enter"],
delegate: true
})
_on(n12, "keyup", () => _ctx.handleEvent, {
keys: ["tab"],
delegate: true
})
_on(n13, "keyup", () => _ctx.handleEvent, {
keys: ["delete"],
delegate: true
})
_on(n14, "keyup", () => _ctx.handleEvent, {
keys: ["esc"],
delegate: true
})
_on(n15, "keyup", () => _ctx.handleEvent, {
keys: ["space"],
delegate: true
})
_on(n16, "keyup", () => _ctx.handleEvent, {
keys: ["up"],
delegate: true
})
_on(n17, "keyup", () => _ctx.handleEvent, {
keys: ["down"],
delegate: true
})
_on(n18, "keyup", () => _ctx.handleEvent, {
keys: ["left"],
delegate: true
})
_on(n19, "keyup", () => _ctx.submit, {
modifiers: ["middle"],
delegate: true
})
_on(n20, "keyup", () => _ctx.submit, {
modifiers: ["middle", "self"],
delegate: true
})
_on(n21, "keyup", () => _ctx.handleEvent, {
modifiers: ["self"],
keys: ["enter"],
delegate: true
})
return [n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21]
}"
`;
exports[`v-on > function expression w/ prefixIdentifiers: true 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => e => _ctx.foo(e)))
_on(n0, "click", () => e => _ctx.foo(e), {
delegate: true
})
return n0
}"
`;
exports[`v-on > inline statement w/ prefixIdentifiers: true 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => (_ctx.foo($event))))
_on(n0, "click", () => $event => (_ctx.foo($event)), {
delegate: true
})
return n0
}"
`;
exports[`v-on > multiple inline statements w/ prefixIdentifiers: true 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => {_ctx.foo($event);_ctx.bar()}))
_on(n0, "click", () => $event => {_ctx.foo($event);_ctx.bar()}, {
delegate: true
})
return n0
}"
`;
exports[`v-on > should NOT add a prefix to $event if the expression is a function expression 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => {_ctx.i++;_ctx.foo($event)}))
_on(n0, "click", () => $event => {_ctx.i++;_ctx.foo($event)}, {
delegate: true
})
return n0
}"
`;
exports[`v-on > should NOT wrap as function if expression is already function expression (with Typescript) 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => (e: any): any => _ctx.foo(e)))
_on(n0, "click", () => (e: any): any => _ctx.foo(e), {
delegate: true
})
return n0
}"
`;
exports[`v-on > should NOT wrap as function if expression is already function expression (with newlines) 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() =>
_on(n0, "click", () =>
$event => {
_ctx.foo($event)
}
))
, {
delegate: true
})
return n0
}"
`;
exports[`v-on > should NOT wrap as function if expression is already function expression 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => _ctx.foo($event)))
_on(n0, "click", () => $event => _ctx.foo($event), {
delegate: true
})
return n0
}"
`;
exports[`v-on > should NOT wrap as function if expression is complex member expression 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.a['b' + _ctx.c]))
_on(n0, "click", () => _ctx.a['b' + _ctx.c], {
delegate: true
})
return n0
}"
`;
exports[`v-on > should delegate event 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.test))
_on(n0, "click", () => _ctx.test, {
delegate: true
})
return n0
}"
`;
exports[`v-on > should handle multi-line statement 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => {
_on(n0, "click", () => $event => {
_ctx.foo();
_ctx.bar()
}))
}, {
delegate: true
})
return n0
}"
`;
exports[`v-on > should handle multiple inline statement 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => {_ctx.foo();_ctx.bar()}))
_on(n0, "click", () => $event => {_ctx.foo();_ctx.bar()}, {
delegate: true
})
return n0
}"
`;
exports[`v-on > should not prefix member expression 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.foo.bar))
_on(n0, "click", () => _ctx.foo.bar, {
delegate: true
})
return n0
}"
`;
exports[`v-on > should not wrap keys guard if no key modifier is present 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("keyup")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "keyup", _eventHandler(() => _ctx.test, {
modifiers: ["exact"]
}))
_on(n0, "keyup", () => _ctx.test, {
modifiers: ["exact"],
delegate: true
})
return n0
}"
`;
exports[`v-on > should support multiple events and modifiers options w/ prefixIdentifiers: true 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click", "keyup")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.test, {
modifiers: ["stop"]
}))
_recordMetadata(n0, "events", "keyup", _eventHandler(() => _ctx.test, {
keys: ["enter"]
}))
_on(n0, "click", () => _ctx.test, {
modifiers: ["stop"],
delegate: true
})
_on(n0, "keyup", () => _ctx.test, {
keys: ["enter"],
delegate: true
})
return n0
}"
`;
@ -329,23 +382,26 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
_on(n0, "click", () => _ctx.test, { capture: true, once: true }, {
modifiers: ["stop", "prevent"]
_on(n0, "click", () => _ctx.test, {
modifiers: ["stop", "prevent"],
capture: true,
once: true
})
return n0
}"
`;
exports[`v-on > should transform click.middle 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("mouseup")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "mouseup", _eventHandler(() => _ctx.test, {
modifiers: ["middle"]
}))
_on(n0, "mouseup", () => _ctx.test, {
modifiers: ["middle"],
delegate: true
})
return n0
}"
`;
@ -357,7 +413,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
_renderEffect(() => {
_on(n0, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), () => _ctx.test, undefined, {
_on(n0, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), () => _ctx.test, {
modifiers: ["middle"]
})
})
@ -366,15 +422,16 @@ export function render(_ctx) {
`;
exports[`v-on > should transform click.right 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("contextmenu")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "contextmenu", _eventHandler(() => _ctx.test, {
modifiers: ["right"]
}))
_on(n0, "contextmenu", () => _ctx.test, {
modifiers: ["right"],
delegate: true
})
return n0
}"
`;
@ -386,8 +443,8 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
_renderEffect(() => {
_on(n0, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), () => _ctx.test, undefined, {
modifiers: ["right"],
_on(n0, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), () => _ctx.test, {
modifiers: ["right"],
keys: ["right"]
})
})
@ -396,13 +453,15 @@ export function render(_ctx) {
`;
exports[`v-on > should wrap as function if expression is inline statement 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => (_ctx.i++)))
_on(n0, "click", () => $event => (_ctx.i++), {
delegate: true
})
return n0
}"
`;
@ -414,8 +473,8 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
_renderEffect(() => {
_on(n0, _ctx.e, () => _ctx.test, undefined, {
modifiers: ["left"],
_on(n0, _ctx.e, () => _ctx.test, {
modifiers: ["left"],
keys: ["left"]
})
})
@ -428,9 +487,15 @@ exports[`v-on > should wrap in unref if identifier is setup-maybe-ref w/ inline:
const n0 = t0()
const n1 = t0()
const n2 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => $event => (x.value=_unref(y))))
_recordMetadata(n1, "events", "click", _eventHandler(() => $event => (x.value++)))
_recordMetadata(n2, "events", "click", _eventHandler(() => $event => ({ x: x.value } = _unref(y))))
_on(n0, "click", () => $event => (x.value=_unref(y)), {
delegate: true
})
_on(n1, "click", () => $event => (x.value++), {
delegate: true
})
_on(n2, "click", () => $event => ({ x: x.value } = _unref(y)), {
delegate: true
})
return [n0, n1, n2]
})()"
`;
@ -441,36 +506,40 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
_on(n0, "keydown", () => _ctx.test, { capture: true }, {
modifiers: ["stop", "ctrl"],
keys: ["a"]
_on(n0, "keydown", () => _ctx.test, {
modifiers: ["stop", "ctrl"],
keys: ["a"],
capture: true
})
return n0
}"
`;
exports[`v-on > should wrap keys guard for static key event w/ left/right modifiers 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("keyup")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "keyup", _eventHandler(() => _ctx.test, {
keys: ["left"]
}))
_on(n0, "keyup", () => _ctx.test, {
keys: ["left"],
delegate: true
})
return n0
}"
`;
exports[`v-on > simple expression 1`] = `
"import { recordMetadata as _recordMetadata, eventHandler as _eventHandler, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.handleClick))
_on(n0, "click", () => _ctx.handleClick, {
delegate: true
})
return n0
}"
`;

View File

@ -26,7 +26,7 @@ describe('v-on', () => {
)
expect(code).matchSnapshot()
expect(vaporHelpers).not.contains('on')
expect(vaporHelpers).contains('on')
expect(helpers.size).toBe(0)
expect(ir.block.effect).toEqual([])
expect(ir.block.operation).toMatchObject([
@ -155,7 +155,7 @@ describe('v-on', () => {
compileWithVOn(`<div @click="i++"/>`)
expect(code).matchSnapshot()
expect(vaporHelpers).not.contains('on')
expect(vaporHelpers).contains('on')
expect(helpers.size).toBe(0)
expect(ir.block.effect).toEqual([])
expect(ir.block.operation).toMatchObject([
@ -171,7 +171,9 @@ describe('v-on', () => {
},
])
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => $event => (_ctx.i++)))',
`_on(n0, "click", () => $event => (_ctx.i++), {
delegate: true
})`,
)
})
@ -188,18 +190,19 @@ describe('v-on', () => {
},
)
expect(code).matchSnapshot()
expect(vaporHelpers).contains('unref')
expect(helpers.size).toBe(0)
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => $event => (x.value=_unref(y))))',
)
expect(code).contains(
'_recordMetadata(n1, "events", "click", _eventHandler(() => $event => (x.value++)))',
)
expect(code).contains(
'_recordMetadata(n2, "events", "click", _eventHandler(() => $event => ({ x: x.value } = _unref(y))))',
)
expect(code)
.contains(`_on(n0, "click", () => $event => (x.value=_unref(y)), {
delegate: true
})`)
expect(code).contains(`_on(n1, "click", () => $event => (x.value++), {
delegate: true
})`)
expect(code)
.contains(`_on(n2, "click", () => $event => ({ x: x.value } = _unref(y)), {
delegate: true
})`)
})
test('should handle multiple inline statement', () => {
@ -216,7 +219,9 @@ describe('v-on', () => {
// in this case the return value is discarded and the behavior is
// consistent with 2.x
expect(code).contains(
`_recordMetadata(n0, "events", "click", _eventHandler(() => $event => {_ctx.foo();_ctx.bar()}))`,
`_on(n0, "click", () => $event => {_ctx.foo();_ctx.bar()}, {
delegate: true
})`,
)
})
@ -234,7 +239,12 @@ describe('v-on', () => {
// in this case the return value is discarded and the behavior is
// consistent with 2.x
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => $event => {\n_ctx.foo();\n_ctx.bar()\n})',
`_on(n0, "click", () => $event => {
_ctx.foo();
_ctx.bar()
}, {
delegate: true
})`,
)
})
@ -252,7 +262,9 @@ describe('v-on', () => {
])
// should NOT prefix $event
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => $event => (_ctx.foo($event))))',
`_on(n0, "click", () => $event => (_ctx.foo($event)), {
delegate: true
})`,
)
})
@ -270,7 +282,9 @@ describe('v-on', () => {
])
// should NOT prefix $event
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => $event => {_ctx.foo($event);_ctx.bar()}))',
`_on(n0, "click", () => $event => {_ctx.foo($event);_ctx.bar()}, {
delegate: true
})`,
)
})
@ -285,7 +299,9 @@ describe('v-on', () => {
},
])
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => $event => _ctx.foo($event)))',
`_on(n0, "click", () => $event => _ctx.foo($event), {
delegate: true
})`,
)
})
@ -303,7 +319,9 @@ describe('v-on', () => {
},
])
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => (e: any): any => _ctx.foo(e)))',
`_on(n0, "click", () => (e: any): any => _ctx.foo(e), {
delegate: true
})`,
)
})
@ -370,7 +388,9 @@ describe('v-on', () => {
expect(code).matchSnapshot()
expect(code).contains(
`_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.a['b' + _ctx.c]))`,
`_on(n0, "click", () => _ctx.a['b' + _ctx.c], {
delegate: true
})`,
)
})
@ -387,7 +407,9 @@ describe('v-on', () => {
},
])
expect(code).contains(
'_recordMetadata(n0, "events", "click", _eventHandler(() => e => _ctx.foo(e)))',
`_on(n0, "click", () => e => _ctx.foo(e), {
delegate: true
})`,
)
})
@ -443,9 +465,12 @@ describe('v-on', () => {
},
])
expect(code).contains(
'_on(n0, "click", () => _ctx.test, { capture: true, once: true }, {',
`_on(n0, "click", () => _ctx.test, {
modifiers: ["stop", "prevent"],
capture: true,
once: true
})`,
)
expect(code).contains('modifiers: ["stop", "prevent"]')
})
test('should support multiple events and modifiers options w/ prefixIdentifiers: true', () => {
@ -497,14 +522,16 @@ describe('v-on', () => {
expect(code).matchSnapshot()
expect(code).contains(
`_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.test, {`,
`_on(n0, "click", () => _ctx.test, {
modifiers: ["stop"],
delegate: true
})`,
)
expect(code).contains(`modifiers: ["stop"]`)
expect(code).contains(
`_recordMetadata(n0, "events", "keyup", _eventHandler(() => _ctx.test, {`,
)
expect(code).contains(`keys: ["enter"]`)
expect(code).contains(`_on(n0, "keyup", () => _ctx.test, {
keys: ["enter"],
delegate: true
})`)
})
test('should wrap keys guard for keyboard events or dynamic events', () => {
@ -686,9 +713,8 @@ describe('v-on', () => {
})
expect(code).matchSnapshot()
expect(code).contains(
`_recordMetadata(n0, "events", "click", _eventHandler(() => _ctx.foo.bar))`,
)
expect(code).contains(`_on(n0, "click", () => _ctx.foo.bar, {`)
expect(code).contains(`delegate: true`)
})
test('should delegate event', () => {

View File

@ -7,78 +7,49 @@ import {
INDENT_END,
INDENT_START,
NEWLINE,
buildCodeFragment,
genCall,
genMulti,
} from './utils'
export function genSetEvent(
oper: SetEventIRNode,
context: CodegenContext,
): CodeFragment[] {
const { vaporHelper, options: ctxOptions } = context
const { keys, nonKeys, options } = oper.modifiers
const { vaporHelper, options } = context
const { element, key, keyOverride, value, modifiers, delegate } = oper
const name = genName()
const handler = genEventHandler()
const modifierOptions = genModifierOptions()
if (oper.delegate) {
// oper.key is static
context.delegates.add(oper.key.content)
return [
NEWLINE,
...genCall(
vaporHelper('recordMetadata'),
`n${oper.element}`,
'"events"',
name,
genCall(vaporHelper('eventHandler'), handler, modifierOptions),
),
]
}
const handlerOptions = options.length
? `{ ${options.map(v => `${v}: true`).join(', ')} }`
: modifierOptions
? 'undefined'
: undefined
const eventOptions = genEventOptions()
return [
NEWLINE,
...genCall(
vaporHelper('on'),
`n${oper.element}`,
name,
handler,
handlerOptions,
modifierOptions,
),
...genCall(vaporHelper('on'), `n${element}`, name, handler, eventOptions),
]
function genName(): CodeFragment[] {
const expr = genExpression(oper.key, context)
if (oper.keyOverride) {
const expr = genExpression(key, context)
if (keyOverride) {
// TODO unit test
const find = JSON.stringify(oper.keyOverride[0])
const replacement = JSON.stringify(oper.keyOverride[1])
const find = JSON.stringify(keyOverride[0])
const replacement = JSON.stringify(keyOverride[1])
const wrapped: CodeFragment[] = ['(', ...expr, ')']
return [...wrapped, ` === ${find} ? ${replacement} : `, ...wrapped]
} else {
return genExpression(oper.key, context)
return genExpression(key, context)
}
}
function genEventHandler() {
const exp = oper.value
if (exp && exp.content.trim()) {
const isMemberExp = isMemberExpression(exp.content, ctxOptions)
const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content))
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(exp, context), {
const expr = context.withId(() => genExpression(value, context), {
$event: null,
})
const hasMultipleStatements = exp.content.includes(`;`)
const hasMultipleStatements = value.content.includes(`;`)
return [
'() => $event => ',
hasMultipleStatements ? '{' : '(',
@ -86,28 +57,33 @@ export function genSetEvent(
hasMultipleStatements ? '}' : ')',
]
} else {
return ['() => ', ...genExpression(exp, context)]
return ['() => ', ...genExpression(value, context)]
}
}
return ['() => {}']
}
function genModifierOptions() {
const hasOptions = nonKeys.length || keys.length
if (!hasOptions) return
const [frag, push] = buildCodeFragment('{', INDENT_START)
if (nonKeys.length) {
push(NEWLINE, 'modifiers: ', genArrayExpression(nonKeys))
function genEventOptions(): CodeFragment[] | undefined {
let { options, keys, nonKeys } = modifiers
if (delegate) {
// key is static
context.delegates.add(key.content)
options = [...options, 'delegate']
}
if (keys.length && nonKeys.length) {
push(',')
}
if (keys.length) {
push(NEWLINE, 'keys: ', genArrayExpression(keys))
}
push(INDENT_END, NEWLINE, '}')
return frag
if (!options.length && !nonKeys.length && !keys.length) return
return genMulti(
[
['{', INDENT_START, NEWLINE],
[INDENT_END, NEWLINE, '}'],
[', ', NEWLINE],
],
!!nonKeys.length && ['modifiers: ', genArrayExpression(nonKeys)],
!!keys.length && ['keys: ', genArrayExpression(keys)],
...options.map((option): CodeFragment[] => [`${option}: true`]),
)
}
}

View File

@ -32,24 +32,28 @@ export function buildCodeFragment(...frag: CodeFragment[]) {
export function genMulti(
[left, right, seg]: [
left: CodeFragment,
right: CodeFragment,
segment: CodeFragment,
left: CodeFragments,
right: CodeFragments,
segment: CodeFragments,
],
...fns: CodeFragments[]
): CodeFragment[] {
const frag: CodeFragment[] = []
fns = fns.filter(Boolean)
frag.push(left)
push(left)
for (let [i, fn] of (
fns as Array<Exclude<CodeFragments, FalsyValue>>
).entries()) {
push(fn)
if (i < fns.length - 1) push(seg)
}
push(right)
return frag
function push(fn: CodeFragments) {
if (!isArray(fn)) fn = [fn]
frag.push(...fn)
if (i < fns.length - 1) frag.push(seg)
}
frag.push(right)
return frag
}
export function genCall(

View File

@ -1,4 +1,4 @@
import { append, insert, normalizeBlock, prepend, remove } from '../src/dom'
import { append, insert, normalizeBlock, prepend, remove } from '../src/dom/dom'
import { fragmentKey } from '../src/render'
const node1 = document.createTextNode('node1')

View File

@ -1,6 +1,5 @@
import { NOOP } from '@vue/shared'
import {
setDynamicProp as _setDynamicProp,
setAttr,
setClass,
setDOMProp,
@ -9,6 +8,7 @@ import {
setStyle,
setText,
} from '../../src'
import { setDynamicProp as _setDynamicProp } from '../../src/dom/prop'
import {
createComponentInstance,
setCurrentInstance,

View File

@ -1,10 +1,5 @@
import { isArray, toDisplayString } from '@vue/shared'
import type { Block } from './render'
export * from './dom/style'
export * from './dom/prop'
export * from './dom/event'
export * from './dom/templateRef'
import type { Block } from '../render'
/*! #__NO_SIDE_EFFECTS__ */
export function normalizeBlock(block: Block): Node[] {

View File

@ -22,28 +22,39 @@ interface ModifierOptions {
keys?: string[]
}
interface EventOptions extends AddEventListenerOptions, ModifierOptions {
delegate?: boolean
}
export type DelegatedHandler = {
(...args: any[]): any
delegate?: boolean
}
export function on(
el: HTMLElement,
event: string,
handlerGetter: () => undefined | ((...args: any[]) => any),
options?: AddEventListenerOptions,
modifierOptions?: ModifierOptions,
options: EventOptions = {},
) {
const handler = eventHandler(handlerGetter, modifierOptions)
const handler: DelegatedHandler = eventHandler(handlerGetter, options)
handler.delegate = options.delegate
recordMetadata(el, 'events', event, handler)
const cleanup = addEventListener(el, event, handler, options)
const scope = getCurrentScope()
const effect = getCurrentEffect()
if (!options.delegate) {
const cleanup = addEventListener(el, event, handler, options)
const scope = getCurrentScope()
const effect = getCurrentEffect()
if (effect && effect.scope === scope) {
onEffectCleanup(cleanup)
} else if (scope) {
onScopeDispose(cleanup)
if (effect && effect.scope === scope) {
onEffectCleanup(cleanup)
} else if (scope) {
onScopeDispose(cleanup)
}
}
}
export function eventHandler(
function eventHandler(
getter: () => undefined | ((...args: any[]) => any),
{ modifiers, keys }: ModifierOptions = {},
) {
@ -51,12 +62,8 @@ export function eventHandler(
let handler = getter()
if (!handler) return
if (modifiers) {
handler = withModifiers(handler, modifiers)
}
if (keys) {
handler = withKeys(handler, keys)
}
if (modifiers) handler = withModifiers(handler, modifiers)
if (keys) handler = withKeys(handler, keys)
handler && handler(...args)
}
}
@ -92,8 +99,8 @@ const delegatedEventHandler = (e: Event) => {
},
})
while (node !== null) {
const handler = getMetadata(node).events[e.type] as (...args: any[]) => any
if (handler && !node.disabled) {
const handler = getMetadata(node).events[e.type]
if (handler && handler.delegate && !node.disabled) {
handler(e)
if (e.cancelBubble) return
}

View File

@ -1,6 +1,6 @@
import { type EffectScope, effectScope, isReactive } from '@vue/reactivity'
import { isArray } from '@vue/shared'
import { createComment, createTextNode, insert, remove } from './dom'
import { createComment, createTextNode, insert, remove } from './dom/dom'
import { renderEffect } from './renderWatch'
import { type Block, type Fragment, fragmentKey } from './render'

View File

@ -1,7 +1,7 @@
import { renderWatch } from './renderWatch'
import { type Block, type Fragment, fragmentKey } from './render'
import { type EffectScope, effectScope } from '@vue/reactivity'
import { createComment, createTextNode, insert, remove } from './dom'
import { createComment, createTextNode, insert, remove } from './dom/dom'
type BlockFn = () => Block

View File

@ -52,12 +52,25 @@ export * from './renderWatch'
export * from './template'
export * from './apiWatch'
export * from './directive'
export * from './dom'
export { insert, prepend, append, remove, createTextNode } from './dom/dom'
export { setStyle } from './dom/style'
export {
setText,
setHtml,
setClass,
setAttr,
setDOMProp,
setDynamicProp,
setDynamicProps,
} from './dom/prop'
export { on, delegateEvents } from './dom/event'
export { setRef } from './dom/templateRef'
export * from './apiLifecycle'
export * from './if'
export * from './for'
export { defineComponent } from './apiDefineComponent'
export { recordMetadata } from './metadata'
export * from './directives/vShow'
export * from './directives/vModel'

View File

@ -1,8 +1,9 @@
import type { Data } from '@vue/shared'
import type { DelegatedHandler } from './dom/event'
export interface ElementMetadata {
props: Data
events: Data
events: Record<string, DelegatedHandler>
}
export function getMetadata(

View File

@ -15,7 +15,7 @@ import {
} from './component'
import { initProps } from './componentProps'
import { invokeDirectiveHook } from './directive'
import { insert, querySelector, remove } from './dom'
import { insert, querySelector, remove } from './dom/dom'
import { queuePostRenderEffect } from './scheduler'
export const fragmentKey = Symbol(__DEV__ ? `fragmentKey` : ``)

View File

@ -13,7 +13,8 @@ const remaining = computed(() => {
return tasks.value.filter(task => !task.completed).length
})
function handleAdd() {
function handleAdd(evt: MouseEvent) {
console.log(evt)
tasks.value.push({
title: value.value,
completed: false,
@ -67,7 +68,7 @@ function handleRemove(idx: number, task: Task) {
@keydown.enter="handleAdd"
placeholder="What need to be done?"
/>
<button @click="handleAdd">Add</button>
<button @click.passive="handleAdd">Add</button>
<button @click="handleClearComplete">Clear completed</button>
<button @click="handleClearAll">Clear all</button>
</div>

View File

@ -48,7 +48,7 @@ export default defineComponent({
on(input, 'input', () => e => {
value.value = e.target.value
})
on(input, 'keydown', () => handleAdd, undefined, {
on(input, 'keydown', () => handleAdd, {
keys: ['enter'],
})