8000 v-on: support .stop and .prevent modifiers · bencode/vue@d0c916f · GitHub
[go: up one dir, main page]

Skip to content

Commit d0c916f

Browse files
committed
v-on: support .stop and .prevent modifiers
1 parent e421cb6 commit d0c916f

File tree

2 files changed

+102
-17
lines changed

2 files changed

+102
-17
lines changed

src/directives/public/on.js

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
var _ = require('../../util')
22

3+
// modifiers
4+
var stopRE = /\.stop\b/
5+
var preventRE = /\.prevent\b/
6+
7+
// keyCode aliases
38
var keyCodes = {
49
esc: 27,
510
tab: 9,
@@ -12,15 +17,6 @@ var keyCodes = {
1217
down: 40
1318
}
1419

15-
/**
16-
* Wrap a handler function so that it only gets triggered on
17-
* specified keypress events.
18-
*
19-
* @param {Function} handler
20-
* @param {String|Number} key
21-
* @return {Function}
22-
*/
23-
2420
function keyFilter (handler, key) {
2521
var code = keyCodes[key]
2622
if (!code) {
@@ -33,18 +29,48 @@ function keyFilter (handler, key) {
3329
}
3430
}
3531

32+
function stopFilter (handler) {
33+
return function (e) {
34+
e.stopPropagation()
35+
return handler.call(this, e)
36+
}
37+
}
38+
39+
function preventFilter (handler) {
40+
return function (e) {
41+
e.preventDefault()
42+
return handler.call(this, e)
43+
}
44+
}
45+
3646
module.exports = {
3747

3848
acceptStatement: true,
3949
priority: 700,
4050

4151
bind: function () {
4252
// 1.0.0 key filter
43-
var rawEvent = this.event = this.arg
44-
var keyIndex = rawEvent.indexOf('.')
53+
var event = this.arg
54+
55+
// stop modifier
56+
if (stopRE.test(event)) {
57+
this.stop = true
58+
event = event.replace(stopRE, '')
59+
}
60+
61+
// prevent modifier
62+
if (preventRE.test(event)) {
63+
this.prevent = true
64+
event = event.replace(preventRE, '')
65+
}
66+
67+
// key modifier
68+
var keyIndex = event.indexOf('.')
4569
if (keyIndex > -1) {
46-
this.event = rawEvent.slice(0, keyIndex)
47-
this.key = rawEvent.slice(keyIndex + 1)
70+
this.event = event.slice(0, keyIndex)
71+
this.key = event.slice(keyIndex + 1)
72+
} else {
73+
this.event = event
4874
}
4975

5076
// deal with iframes
@@ -63,13 +89,20 @@ module.exports = {
6389
update: function (handler) {
6490
if (typeof handler !== 'function') {
6591
process.env.NODE_ENV !== 'production' && _.warn(
66-
'on-"' + this.event + '="' +
92+
'v-on:' + this.event + '="' +
6793
this.expression + '" expects a function value, ' +
6894
'got ' + handler
6995
)
7096
return
7197
}
7298

99+
// apply modifiers
100+
if (this.stop) {
101+
handler = stopFilter(handler)
102+
}
103+
if (this.prevent) {
104+
handler = preventFilter(handler)
105+
}
73106
if (this.key) {
74107
handler = keyFilter(handler, this.key)
75108
}

test/unit/specs/directives/public/on_spec.js

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ A3E2 if (_.inBrowser) {
6868
})
6969
})
7070

71-
it('with key filter', function (done) {
71+
it('with key modifier', function (done) {
7272
new Vue({
7373
el: el,
7474
template: '<a v-on:keyup.enter="test">{{a}}</a>',
@@ -89,7 +89,7 @@ if (_.inBrowser) {
8989
})
9090
})
9191

92-
it('with key filter (keycode)', function (done) {
92+
it('with key modifier (keycode)', function (done) {
9393
new Vue({
9494
el: el,
9595
template: '<a v-on:keyup.13="test">{{a}}</a>',
@@ -110,7 +110,59 @@ if (_.inBrowser) {
110110
})
111111
})
112112

113-
it('warn nv-on:function values', function () {
113+
it('stop modifier', function () {
114+
var outer = jasmine.createSpy('outer')
115+
var inner = jasmine.createSpy('inner')
116+
new Vue({
117+
el: el,
118+
template: '<div @click="outer"><div class="inner" @click.stop="inner"></div></div>',
119+
methods: {
120+
outer: outer,
121+
inner: inner
122+
}
123+
})
124+
trigger(el.querySelector('.inner'), 'click')
125+
expect(inner).toHaveBeenCalled()
126+
expect(outer).not.toHaveBeenCalled()
127+
})
128+
129+
it('prevent modifier', function () {
130+
var event
131+
new Vue({
132+
el: el,
133+
template: '<a href="#" @click.prevent="onClick">',
134+
methods: {
135+
onClick: function (e) {
136+
event = e
137+
}
138+
}
139+
})
140+
trigger(el.firstChild, 'click')
141+
expect(event.defaultPrevented).toBe(true)
142+
})
143+
144+
it('multiple modifiers working together', function () {
145+
var outer = jasmine.createSpy('outer')
146+
var event
147+
new Vue({
148+
el: el,
149+
template: '<div @keyup="outer"><input class="inner" @keyup.enter.stop.prevent="inner"></div></div>',
150+
methods: {
151+
outer: outer,
152+
inner: function (e) {
153+
event = e
154+
}
155+
}
156+
})
157+
trigger(el.querySelector('.inner'), 'keyup', function (e) {
158+
e.keyCode = 13
159+
})
160+
expect(outer).not.toHaveBeenCalled()
161+
expect(event).toBeTruthy()
162+
expect(event.defaultPrevented).toBe(true)
163+
})
164+
165+
it('warn non-function values', function () {
114166
new Vue({
115167
el: el,
116168
data: { test: 123 },

0 commit comments

Comments
 (0)
0