diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index 6a64e1a1919..67ae0368b65 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -87,6 +87,14 @@ function genHandler ( if (keyCodes[key]) { keys.push(key) } + } else if (key === 'exact') { + const modifiers: ASTModifiers = (handler.modifiers: any) + genModifierCode += genGuard( + ['ctrl', 'shift', 'alt', 'meta'] + .filter(keyModifier => !modifiers[keyModifier]) + .map(keyModifier => `$event.${keyModifier}Key`) + .join('||') + ) } else { keys.push(key) } diff --git a/src/core/instance/proxy.js b/src/core/instance/proxy.js index 51c880f3e0a..7454712f994 100644 --- a/src/core/instance/proxy.js +++ b/src/core/instance/proxy.js @@ -29,7 +29,7 @@ if (process.env.NODE_ENV !== 'production') { Proxy.toString().match(/native code/) if (hasProxy) { - const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta') + const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact') config.keyCodes = new Proxy(config.keyCodes, { set (target, key, value) { if (isBuiltInModifier(key)) { diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index f22a47e9ea7..5dd0f1ce409 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -205,6 +205,96 @@ describe('Directive v-on', () => { expect(spy).toHaveBeenCalled() }) + // ctrl, shift, alt, meta + it('should support system modifers', () => { + vm = new Vue({ + el, + template: ` +
+ + + + +
+ `, + methods: { foo: spy } + }) + + triggerEvent(vm.$refs.ctrl, 'keyup') + expect(spy.calls.count()).toBe(0) + triggerEvent(vm.$refs.ctrl, 'keyup', e => { e.ctrlKey = true }) + expect(spy.calls.count()).toBe(1) + + triggerEvent(vm.$refs.shift, 'keyup') + expect(spy.calls.count()).toBe(1) + triggerEvent(vm.$refs.shift, 'keyup', e => { e.shiftKey = true }) + expect(spy.calls.count()).toBe(2) + + triggerEvent(vm.$refs.alt, 'keyup') + expect(spy.calls.count()).toBe(2) + triggerEvent(vm.$refs.alt, 'keyup', e => { e.altKey = true }) + expect(spy.calls.count()).toBe(3) + + triggerEvent(vm.$refs.meta, 'keyup') + expect(spy.calls.count()).toBe(3) + triggerEvent(vm.$refs.meta, 'keyup', e => { e.metaKey = true }) + expect(spy.calls.count()).toBe(4) + }) + + it('should support exact modifier', () => { + vm = new Vue({ + el, + template: ` +
+ +
+ `, + methods: { foo: spy } + }) + + triggerEvent(vm.$refs.ctrl, 'keyup') + expect(spy.calls.count()).toBe(1) + + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + }) + expect(spy.calls.count()).toBe(1) + + // should not trigger if has other system modifiers + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + e.altKey = true + }) + expect(spy.calls.count()).toBe(1) + }) + + it('should support system modifers with exact', () => { + vm = new Vue({ + el, + template: ` +
+ +
+ `, + methods: { foo: spy } + }) + + triggerEvent(vm.$refs.ctrl, 'keyup') + expect(spy.calls.count()).toBe(0) + + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + }) + expect(spy.calls.count()).toBe(1) + + // should not trigger if has other system modifiers + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + e.altKey = true + }) + expect(spy.calls.count()).toBe(1) + }) + it('should support number keyCode', () => { vm = new Vue({ el, @@ -497,8 +587,8 @@ describe('Directive v-on', () => { }).not.toThrow() }) - // GitHub Issue #5046 - it('should support keyboard modifier', () => { + // Github Issue #5046 + it('should support keyboard modifier for direction keys', () => { const spyLeft = jasmine.createSpy() const spyRight = jasmine.createSpy() const spyUp = jasmine.createSpy() diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index 8b415a13ebd..4eb804c3d36 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -312,6 +312,14 @@ describe('codegen', () => { '', `with(this){return _c('input',{on:{"click":function($event){if(!$event.metaKey)return null;onClick($event)}}})}` ) + assertCodegen( + '', + `with(this){return _c('input',{on:{"click":function($event){if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey)return null;onClick($event)}}})}` + ) + assertCodegen( + '', + `with(this){return _c('input',{on:{"click":function($event){if(!$event.ctrlKey)return null;if($event.shiftKey||$event.altKey||$event.metaKey)return null;onClick($event)}}})}` + ) }) it('generate events with multiple modifiers', () => {