Skip to content

Commit beee7d8

Browse files
Kingwlyyx990803
authored andcommitted
support v-on passive modifier (#5132)
* support v-on passive modifier * fix supportsPassive and run unit when the test browser supports * add mutual exclusive warning * Fix typo * Fix typo * Remove extra line - CS fix
1 parent 354c2f4 commit beee7d8

File tree

5 files changed

+67
-6
lines changed

5 files changed

+67
-6
lines changed

src/compiler/helpers.js

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

3+
import { warn } from 'core/util/index'
34
import { parseFilters } from './parser/filter-parser'
45

56
export function baseWarn (msg: string) {
@@ -41,6 +42,13 @@ export function addHandler (
4142
modifiers: ?ASTModifiers,
4243
important: ?boolean
4344
) {
45+
// warn prevent and passive modifier
46+
if (process.env.NODE_ENV !== 'production' && modifiers && modifiers.prevent && modifiers.passive) {
47+
warn(
48+
'passive and prevent can\'t be used together. ' +
49+
'Passive handler can\'t prevent default event.'
50+
)
51+
}
4452
// check capture modifier
4553
if (modifiers && modifiers.capture) {
4654
delete modifiers.capture
@@ -50,6 +58,10 @@ export function addHandler (
5058
delete modifiers.once
5159
name = '~' + name // mark the event as once
5260
}
61+
if (modifiers && modifiers.passive) {
62+
delete modifiers.passive
63+
name = '&' + name // mark the event as passive
64+
}
5365
let events
5466
if (modifiers && modifiers.native) {
5567
delete modifiers.native

src/core/util/env.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ export const isAndroid = UA && UA.indexOf('android') > 0
1616
export const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA)
1717
export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge
1818

19+
export let supportsPassive = false
20+
if (inBrowser) {
21+
try {
22+
const opts = {}
23+
Object.defineProperty(opts, 'passive', ({
24+
get: function () { supportsPassive = true }
25+
} : Object)) // https://github.com/facebook/flow/issues/285
26+
window.addEventListener('test-passive', null, opts)
27+
} catch (e) {}
28+
}
29+
1930
// this needs to be lazy-evaled because vue may be required before
2031
// vue-server-renderer can set VUE_ENV
2132
let _isServer

src/core/vdom/helpers/update-listeners.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ import { warn } from 'core/util/index'
66
const normalizeEvent = cached((name: string): {
77
name: string,
88
once: boolean,
9-
capture: boolean
9+
capture: boolean,
10+
passive: boolean
1011
} => {
12+
const passive = name.charAt(0) === '&'
13+
name = passive ? name.slice(1) : name
1114
const once = name.charAt(0) === '~' // Prefixed last, checked first
1215
name = once ? name.slice(1) : name
1316
const capture = name.charAt(0) === '!'
1417
name = capture ? name.slice(1) : name
1518
return {
1619
name,
1720
once,
18-
capture
21+
capture,
22+
passive
1923
}
2024
})
2125

@@ -56,7 +60,7 @@ export function updateListeners (
5660
if (!cur.fns) {
5761
cur = on[name] = createFnInvoker(cur)
5862
}
59-
add(event.name, cur, event.once, event.capture)
63+
add(event.name, cur, event.once, event.capture, event.passive)
6064
} else if (cur !== old) {
6165
old.fns = cur
6266
on[name] = old

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* @flow */
22

3-
import { isChrome, isIE } from 'core/util/env'
3+
import { isChrome, isIE, supportsPassive } from 'core/util/env'
44
import { updateListeners } from 'core/vdom/helpers/index'
55
import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model'
66

@@ -31,7 +31,8 @@ function add (
3131
event: string,
3232
handler: Function,
3333
once: boolean,
34-
capture: boolean
34+
capture: boolean,
35+
passive: boolean
3536
) {
3637
if (once) {
3738
const oldHandler = handler
@@ -45,7 +46,7 @@ function add (
4546
}
4647
}
4748
}
48-
target.addEventListener(event, handler, capture)
49+
target.addEventListener(event, handler, supportsPassive ? { capture, passive } : capture)
4950
}
5051

5152
function remove (

test/unit/features/directives/on.spec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Vue from 'vue'
2+
import { supportsPassive } from 'core/util/env'
23

34
describe('Directive v-on', () => {
45
let vm, spy, el
@@ -531,6 +532,38 @@ describe('Directive v-on', () => {
531532
expect(spyDown.calls.count()).toBe(1)
532533
})
533534

535+
// This test case should only run when the test browser supports passive.
536+
if (supportsPassive) {
537+
it('should support passive', () => {
538+
vm = new Vue({
539+
el,
540+
template: `
541+
<div>
542+
<input type="checkbox" ref="normal" @click="foo"/>
543+
<input type="checkbox" ref="passive" @click.passive="foo"/>
544+
<input type="checkbox" ref="exclusive" @click.prevent.passive/>
545+
</div>
546+
`,
547+
methods: {
548+
foo (e) {
549+
e.preventDefault()
550+
}
551+
}
552+
})
553+
554+
vm.$refs.normal.checked = false
555+
vm.$refs.passive.checked = false
556+
vm.$refs.exclusive.checked = false
557+
vm.$refs.normal.click()
558+
vm.$refs.passive.click()
559+
vm.$refs.exclusive.click()
560+
expect(vm.$refs.normal.checked).toBe(false)
561+
expect(vm.$refs.passive.checked).toBe(true)
562+
expect(vm.$refs.exclusive.checked).toBe(true)
563+
expect('passive and prevent can\'t be used together. Passive handler can\'t prevent default event.').toHaveBeenWarned()
564+
})
565+
}
566+
534567
// Github Issues #5146
535568
it('should only prevent when match keycode', () => {
536569
let prevented = false

0 commit comments

Comments
 (0)