From 2bf2a64d33e57e13330b0c60e47654e6934e74fb Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 8 Mar 2017 12:01:27 +0800 Subject: [PATCH 1/6] support v-on passive modifier --- src/compiler/helpers.js | 4 ++++ src/core/util/env.js | 12 +++++++++++ src/core/vdom/helpers/update-listeners.js | 10 ++++++--- src/platforms/web/runtime/modules/events.js | 7 +++--- test/unit/features/directives/on.spec.js | 24 +++++++++++++++++++++ 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/compiler/helpers.js b/src/compiler/helpers.js index 75f55b0ef98..9d8474e79a0 100644 --- a/src/compiler/helpers.js +++ b/src/compiler/helpers.js @@ -50,6 +50,10 @@ export function addHandler ( delete modifiers.once name = '~' + name // mark the event as once } + if (modifiers && modifiers.passive) { + delete modifiers.passive + name = '&' + name // mark the event as passive + } let events if (modifiers && modifiers.native) { delete modifiers.native diff --git a/src/core/util/env.js b/src/core/util/env.js index 7f5302ab465..7be1802a26e 100644 --- a/src/core/util/env.js +++ b/src/core/util/env.js @@ -16,6 +16,18 @@ export const isAndroid = UA && UA.indexOf('android') > 0 export const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA) export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge +let _supportsPassive = false +if (inBrowser) { + try { + const opts = {} + Object.defineProperty(opts, 'passive', ({ + get: function () { _supportsPassive = true } + } : Object)) // https://github.com/facebook/flow/issues/285 + window.addEventListener('test-passive', null, opts) + } catch (e) {} +} +export const supportsPassive = _supportsPassive + // this needs to be lazy-evaled because vue may be required before // vue-server-renderer can set VUE_ENV let _isServer diff --git a/src/core/vdom/helpers/update-listeners.js b/src/core/vdom/helpers/update-listeners.js index 6b5ecd57fc2..14e3c75f076 100644 --- a/src/core/vdom/helpers/update-listeners.js +++ b/src/core/vdom/helpers/update-listeners.js @@ -6,8 +6,11 @@ import { warn } from 'core/util/index' const normalizeEvent = cached((name: string): { name: string, once: boolean, - capture: boolean + capture: boolean, + passive: boolean } => { + const passive = name.charAt(0) === '&' + name = passive ? name.slice(1) : name const once = name.charAt(0) === '~' // Prefixed last, checked first name = once ? name.slice(1) : name const capture = name.charAt(0) === '!' @@ -15,7 +18,8 @@ const normalizeEvent = cached((name: string): { return { name, once, - capture + capture, + passive } }) @@ -56,7 +60,7 @@ export function updateListeners ( if (!cur.fns) { cur = on[name] = createFnInvoker(cur) } - add(event.name, cur, event.once, event.capture) + add(event.name, cur, event.once, event.capture, event.passive) } else if (cur !== old) { old.fns = cur on[name] = old diff --git a/src/platforms/web/runtime/modules/events.js b/src/platforms/web/runtime/modules/events.js index aa5c096ec8c..da632074f95 100644 --- a/src/platforms/web/runtime/modules/events.js +++ b/src/platforms/web/runtime/modules/events.js @@ -1,6 +1,6 @@ /* @flow */ -import { isChrome, isIE } from 'core/util/env' +import { isChrome, isIE, supportsPassive } from 'core/util/env' import { updateListeners } from 'core/vdom/helpers/index' import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model' @@ -31,7 +31,8 @@ function add ( event: string, handler: Function, once: boolean, - capture: boolean + capture: boolean, + passive: boolean ) { if (once) { const oldHandler = handler @@ -45,7 +46,7 @@ function add ( } } } - target.addEventListener(event, handler, capture) + target.addEventListener(event, handler, supportsPassive ? { capture, passive } : capture) } function remove ( diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index 391cb317dee..f99b17c37b7 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -526,4 +526,28 @@ describe('Directive v-on', () => { expect(spyUp.calls.count()).toBe(1) expect(spyDown.calls.count()).toBe(1) }) + + it('should support passive', () => { + vm = new Vue({ + el, + template: ` +
+ + +
+ `, + methods: { + foo (e) { + e.preventDefault() + } + } + }) + + vm.$refs.normal.checked = false + vm.$refs.passive.checked = false + vm.$refs.normal.click() + vm.$refs.passive.click() + expect(vm.$refs.normal.checked).toBe(false) + expect(vm.$refs.passive.checked).toBe(true) + }) }) From ad844ffe0a3eb359a4b36d7aa6c00e9667f61853 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 8 Mar 2017 16:05:19 +0800 Subject: [PATCH 2/6] fix supportsPassive and run unit when the test browser supports --- src/core/util/env.js | 5 ++- test/unit/features/directives/on.spec.js | 46 +++++++++++++----------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/core/util/env.js b/src/core/util/env.js index 7be1802a26e..5970bb85215 100644 --- a/src/core/util/env.js +++ b/src/core/util/env.js @@ -16,17 +16,16 @@ export const isAndroid = UA && UA.indexOf('android') > 0 export const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA) export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge -let _supportsPassive = false +export let supportsPassive = false if (inBrowser) { try { const opts = {} Object.defineProperty(opts, 'passive', ({ - get: function () { _supportsPassive = true } + get: function () { supportsPassive = true } } : Object)) // https://github.com/facebook/flow/issues/285 window.addEventListener('test-passive', null, opts) } catch (e) {} } -export const supportsPassive = _supportsPassive // this needs to be lazy-evaled because vue may be required before // vue-server-renderer can set VUE_ENV diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index f99b17c37b7..c1145635186 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -1,4 +1,5 @@ import Vue from 'vue' +import { supportsPassive } from 'core/util/env' describe('Directive v-on', () => { let vm, spy, spy2, el @@ -527,27 +528,30 @@ describe('Directive v-on', () => { expect(spyDown.calls.count()).toBe(1) }) - it('should support passive', () => { - vm = new Vue({ - el, - template: ` -
- - -
- `, - methods: { - foo (e) { - e.preventDefault() + // This test case should only run when the test browser supports passive. + if (supportsPassive) { + it('should support passive', () => { + vm = new Vue({ + el, + template: ` +
+ + +
+ `, + methods: { + foo (e) { + e.preventDefault() + } } - } - }) + }) - vm.$refs.normal.checked = false - vm.$refs.passive.checked = false - vm.$refs.normal.click() - vm.$refs.passive.click() - expect(vm.$refs.normal.checked).toBe(false) - expect(vm.$refs.passive.checked).toBe(true) - }) + vm.$refs.normal.checked = false + vm.$refs.passive.checked = false + vm.$refs.normal.click() + vm.$refs.passive.click() + expect(vm.$refs.normal.checked).toBe(false) + expect(vm.$refs.passive.checked).toBe(true) + }) + } }) From 9fa45fa916e83d7a5fb2bfc343e2486b9df14654 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 9 Mar 2017 15:38:51 +0800 Subject: [PATCH 3/6] add mutual exclusive warning --- src/compiler/helpers.js | 8 ++++++++ test/unit/features/directives/on.spec.js | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/compiler/helpers.js b/src/compiler/helpers.js index 9d8474e79a0..01e28a9567b 100644 --- a/src/compiler/helpers.js +++ b/src/compiler/helpers.js @@ -1,5 +1,6 @@ /* @flow */ +import { warn } from 'core/util/index' import { parseFilters } from './parser/filter-parser' export function baseWarn (msg: string) { @@ -41,6 +42,13 @@ export function addHandler ( modifiers: ?ASTModifiers, important: ?boolean ) { + // warn prevent and passive modifier + if (process.env.NODE_ENV !== 'production' && modifiers && modifiers.prevent && modifiers.passive) { + warn( + 'passive and prevent can\t be used together. ' + + 'Passive handler can\'t prevent default event.' + ) + } // check capture modifier if (modifiers && modifiers.capture) { delete modifiers.capture diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index c1145635186..a3868a14dd4 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -537,6 +537,7 @@ describe('Directive v-on', () => {
+
`, methods: { @@ -548,10 +549,14 @@ describe('Directive v-on', () => { vm.$refs.normal.checked = false vm.$refs.passive.checked = false + vm.$refs.exclusive.checked = false vm.$refs.normal.click() vm.$refs.passive.click() + vm.$refs.exclusive.click() expect(vm.$refs.normal.checked).toBe(false) expect(vm.$refs.passive.checked).toBe(true) + expect(vm.$refs.exclusive.checked).toBe(true) + expect('passive and prevent can\t be used together. Passive handler can\'t prevent default event.').toHaveBeenWarned() }) } }) From 77db11c0b2cd93553f8024374e4728eb26987c44 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 17 Mar 2017 18:32:13 +0100 Subject: [PATCH 4/6] Fix typo --- src/compiler/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/helpers.js b/src/compiler/helpers.js index 01e28a9567b..89753110c42 100644 --- a/src/compiler/helpers.js +++ b/src/compiler/helpers.js @@ -45,7 +45,7 @@ export function addHandler ( // warn prevent and passive modifier if (process.env.NODE_ENV !== 'production' && modifiers && modifiers.prevent && modifiers.passive) { warn( - 'passive and prevent can\t be used together. ' + + 'passive and prevent can\'t be used together. ' + 'Passive handler can\'t prevent default event.' ) } From c333c6e841180fffa272c7d65c59739c1a4f6ae5 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 17 Mar 2017 18:32:52 +0100 Subject: [PATCH 5/6] Fix typo --- test/unit/features/directives/on.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index a3868a14dd4..e3f03d80cdb 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -556,7 +556,7 @@ describe('Directive v-on', () => { expect(vm.$refs.normal.checked).toBe(false) expect(vm.$refs.passive.checked).toBe(true) expect(vm.$refs.exclusive.checked).toBe(true) - expect('passive and prevent can\t be used together. Passive handler can\'t prevent default event.').toHaveBeenWarned() + expect('passive and prevent can\'t be used together. Passive handler can\'t prevent default event.').toHaveBeenWarned() }) } }) From 0329bcf933c6cbc1a8e9094a016ffcd9eb93ba33 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Mon, 20 Mar 2017 21:48:45 +0530 Subject: [PATCH 6/6] Remove extra line - CS fix --- test/unit/features/directives/on.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index faadeacb721..53d14a59cfa 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -581,5 +581,4 @@ describe('Directive v-on', () => { triggerEvent(vm.$refs.input, 'keydown', e => { e.keyCode = 13 }) expect(prevented).toBe(true) }) - })