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', () => {