Kaynağa Gözat

prohibit replacing Vue.config + support custom keyCodes

Evan You 10 yıl önce
ebeveyn
işleme
4fe51a75a9

+ 1 - 0
flow/component.js

@@ -57,6 +57,7 @@ declare interface Component {
   _isBeingDestroyed: boolean;
   _vnode: ?VNode;
   _staticTrees: ?Array<VNode>;
+  _keyCode: (key: string) => ?number;
 
   // private methods
   // lifecycle

+ 6 - 3
src/compiler/events.js

@@ -53,10 +53,13 @@ function genHandler (
 }
 
 function genKeyFilter (key: string): string {
-  const code = keyCodes[key] || JSON.stringify(key)
+  const code =
+    parseInt(key, 10) || // number keyCode
+    keyCodes[key] || // built-in alias
+    `_keyCode(${JSON.stringify(key)})` // custom alias
   if (Array.isArray(code)) {
-    return `if(${code.map(c => `$event.keyCode!=${c}`).join('&&')})return;`
+    return `if(${code.map(c => `$event.keyCode!==${c}`).join('&&')})return;`
   } else {
-    return `if($event.keyCode!=${code})return;`
+    return `if($event.keyCode!==${code})return;`
   }
 }

+ 9 - 0
src/core/config.js

@@ -3,13 +3,17 @@
 import { no } from 'shared/util'
 
 export type Config = {
+  // user
   optionMergeStrategies: { [key: string]: Function },
   silent: boolean,
   errorHandler: ?Function,
   ignoredElements: ?Array<string>,
+  keyCodes: { [key: string]: number },
+  // platform
   isReservedTag: (x?: string) => boolean,
   isUnknownElement: (x?: string) => boolean,
   mustUseProp: (x?: string) => boolean,
+  // internal
   _assetTypes: Array<string>,
   _lifecycleHooks: Array<string>,
   _maxUpdateCount: number,
@@ -38,6 +42,11 @@ const config: Config = {
    */
   ignoredElements: null,
 
+  /**
+   * Custom user key aliases for v-on
+   */
+  keyCodes: Object.create(null),
+
   /**
    * Check if a tag is reserved so that it cannot be registered as a
    * component. This is platform-dependent and may be overwritten.

+ 11 - 1
src/core/global-api/index.js

@@ -10,7 +10,17 @@ import { set, del } from '../observer/index'
 import builtInComponents from '../components/index'
 
 export function initGlobalAPI (Vue: GlobalAPI) {
-  Vue.config = config
+  // config
+  const configDef = {}
+  configDef.get = () => config
+  if (process.env.NODE_ENV !== 'production') {
+    configDef.set = () => {
+      util.warn(
+        'Do not replace the Vue.config object, set individual fields instead.'
+      )
+    }
+  }
+  Object.defineProperty(Vue, 'config', configDef)
   Vue.util = util
   Vue.set = set
   Vue.delete = del

+ 3 - 0
src/core/instance/render.js

@@ -152,6 +152,9 @@ export function renderMixin (Vue: Class<Component>) {
       }
     }
   }
+
+  // expose v-on keyCodes
+  Vue.prototype._keyCode = key => config.keyCodes[key]
 }
 
 function resolveSlots (

+ 13 - 0
test/unit/features/directives/on.spec.js

@@ -126,6 +126,19 @@ describe('Directive v-on', () => {
     expect(spy).toHaveBeenCalled()
   })
 
+  it('should support custom keyCode', () => {
+    Vue.config.keyCodes.test = 1
+    vm = new Vue({
+      el,
+      template: `<input @keyup.test="foo">`,
+      methods: { foo: spy }
+    })
+    triggerEvent(vm.$el, 'keyup', e => {
+      e.keyCode = 1
+    })
+    expect(spy).toHaveBeenCalled()
+  })
+
   it('should bind to a child component', () => {
     Vue.component('bar', {
       template: '<span>Hello</span>'

+ 7 - 0
test/unit/features/global-api/config.spec.js

@@ -1,6 +1,13 @@
 import Vue from 'vue'
 
 describe('Global config', () => {
+  it('should warn replacing config object', () => {
+    const originalConfig = Vue.config
+    Vue.config = {}
+    expect(Vue.config).toBe(originalConfig)
+    expect('Do not replace the Vue.config object').toHaveBeenWarned()
+  })
+
   describe('silent', () => {
     it('should be false by default', () => {
       Vue.util.warn('foo')

+ 8 - 3
test/unit/modules/compiler/codegen.spec.js

@@ -216,17 +216,22 @@ describe('codegen', () => {
   it('generate events with keycode', () => {
     assertCodegen(
       '<input @input.enter="onInput">',
-      `with(this){return _h(_e('input',{on:{"input":function($event){if($event.keyCode!=13)return;onInput($event)}}}))}`
+      `with(this){return _h(_e('input',{on:{"input":function($event){if($event.keyCode!==13)return;onInput($event)}}}))}`
     )
     // multiple keycodes (delete)
     assertCodegen(
       '<input @input.delete="onInput">',
-      `with(this){return _h(_e('input',{on:{"input":function($event){if($event.keyCode!=8&&$event.keyCode!=46)return;onInput($event)}}}))}`
+      `with(this){return _h(_e('input',{on:{"input":function($event){if($event.keyCode!==8&&$event.keyCode!==46)return;onInput($event)}}}))}`
     )
     // number keycode
     assertCodegen(
       '<input @input.13="onInput">',
-      `with(this){return _h(_e('input',{on:{"input":function($event){if($event.keyCode!="13")return;onInput($event)}}}))}`
+      `with(this){return _h(_e('input',{on:{"input":function($event){if($event.keyCode!==13)return;onInput($event)}}}))}`
+    )
+    // custom keycode
+    assertCodegen(
+      '<input @input.custom="onInput">',
+      `with(this){return _h(_e('input',{on:{"input":function($event){if($event.keyCode!==_keyCode("custom"))return;onInput($event)}}}))}`
     )
   })