Skip to content

Commit 11614d6

Browse files
committed
feat(v-on): support v-on object syntax with no arguments
Note this does not support modifiers and is meant to be used for handling events proxying in higher-order-components.
1 parent b0b6b7e commit 11614d6

File tree

12 files changed

+178
-23
lines changed

12 files changed

+178
-23
lines changed

flow/compiler.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ declare type ASTElement = {
133133
once?: true;
134134
onceProcessed?: boolean;
135135
wrapData?: (code: string) => string;
136+
wrapListeners?: (code: string) => string;
136137

137138
// 2.4 ssr optimization
138139
ssrOptimizability?: number;

flow/component.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ declare interface Component {
121121
_t: (name: string, fallback: ?Array<VNode>, props: ?Object) => ?Array<VNode>;
122122
// apply v-bind object
123123
_b: (data: any, tag: string, value: any, asProp: boolean, isSync?: boolean) => VNodeData;
124+
// apply v-on object
125+
_g: (data: any, value: any) => VNodeData;
124126
// check custom keyCode
125127
_k: (eventKeyCode: number, key: string, builtInAlias: number | Array<number> | void) => boolean;
126128
// resolve scoped slots

flow/vnode.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ declare type VNodeWithData = {
2727
context: Component;
2828
key: string | number | void;
2929
parent?: VNodeWithData;
30+
componentOptions?: VNodeComponentOptions;
3031
componentInstance?: Component;
3132
isRootInsert: boolean;
3233
};

src/compiler/codegen/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* @flow */
22

33
import { genHandlers } from './events'
4-
import { baseWarn, pluckModuleFunction } from '../helpers'
54
import baseDirectives from '../directives/index'
65
import { camelize, no, extend } from 'shared/util'
6+
import { baseWarn, pluckModuleFunction } from '../helpers'
77

88
type TransformFunction = (el: ASTElement, code: string) => string;
99
type DataGenFunction = (el: ASTElement) => string;
@@ -268,6 +268,10 @@ export function genData (el: ASTElement, state: CodegenState): string {
268268
if (el.wrapData) {
269269
data = el.wrapData(data)
270270
}
271+
// v-on data wrap
272+
if (el.wrapListeners) {
273+
data = el.wrapListeners(data)
274+
}
271275
return data
272276
}
273277

src/compiler/directives/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
/* @flow */
22

3+
import on from './on'
34
import bind from './bind'
45
import { noop } from 'shared/util'
56

67
export default {
8+
on,
79
bind,
810
cloak: noop
911
}

src/compiler/directives/on.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* @flow */
2+
3+
import { warn } from 'core/util/index'
4+
5+
export default function on (el: ASTElement, dir: ASTDirective) {
6+
if (process.env.NODE_ENV !== 'production' && dir.modifiers) {
7+
warn(`v-on without argument does not support modifiers.`)
8+
}
9+
el.wrapListeners = (code: string) => `_g(${code},${dir.value})`
10+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* @flow */
2+
3+
import { warn, extend, isPlainObject } from 'core/util/index'
4+
5+
export function bindObjectListeners (data: any, value: any): VNodeData {
6+
if (value) {
7+
if (!isPlainObject(value)) {
8+
process.env.NODE_ENV !== 'production' && warn(
9+
'v-on without argument expects an Object value',
10+
this
11+
)
12+
} else {
13+
const on = data.on = data.on ? extend({}, data.on) : {}
14+
for (const key in value) {
15+
const existing = on[key]
16+
const ours = value[key]
17+
on[key] = existing ? [ours].concat(existing) : ours
18+
}
19+
}
20+
}
21+
return data
22+
}

src/core/instance/render.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { resolveFilter } from './render-helpers/resolve-filter'
2424
import { checkKeyCodes } from './render-helpers/check-keycodes'
2525
import { bindObjectProps } from './render-helpers/bind-object-props'
2626
import { renderStatic, markOnce } from './render-helpers/render-static'
27+
import { bindObjectListeners } from './render-helpers/bind-object-listeners'
2728
import { resolveSlots, resolveScopedSlots } from './render-helpers/resolve-slots'
2829

2930
export function initRender (vm: Component) {
@@ -121,4 +122,5 @@ export function renderMixin (Vue: Class<Component>) {
121122
Vue.prototype._v = createTextVNode
122123
Vue.prototype._e = createEmptyVNode
123124
Vue.prototype._u = resolveScopedSlots
125+
Vue.prototype._g = bindObjectListeners
124126
}

src/core/vdom/create-component.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,8 @@ export function createComponent (
161161
return createFunctionalComponent(Ctor, propsData, data, context, children)
162162
}
163163

164-
// extract listeners, since these needs to be treated as
165-
// child component listeners instead of DOM listeners
164+
// keep listeners
166165
const listeners = data.on
167-
// replace with listeners with .native modifier
168-
data.on = data.nativeOn
169166

170167
if (isTrue(Ctor.options.abstract)) {
171168
// abstract components do not keep anything

src/platforms/web/runtime/modules/events.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,14 @@ function remove (
6666
}
6767

6868
function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {
69-
if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) {
69+
const isComponentRoot = isDef(vnode.componentOptions)
70+
let oldOn = isComponentRoot ? oldVnode.data.nativeOn : oldVnode.data.on
71+
let on = isComponentRoot ? vnode.data.nativeOn : vnode.data.on
72+
if (isUndef(oldOn) && isUndef(on)) {
7073
return
7174
}
72-
const on = vnode.data.on || {}
73-
const oldOn = oldVnode.data.on || {}
75+
on = on || {}
76+
oldOn = oldOn || {}
7477
target = vnode.elm
7578
normalizeEvents(on)
7679
updateListeners(on, oldOn, add, remove, vnode.context)

0 commit comments

Comments
 (0)