prohibit replacing Vue.config + support custom keyCodes

This commit is contained in:
Evan You 2016-06-22 11:35:33 -04:00
parent 63da54ddee
commit 4fe51a75a9
8 changed files with 58 additions and 7 deletions

View File

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

View File

@ -53,10 +53,13 @@ function genHandler (
} }
function genKeyFilter (key: string): string { 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)) { 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 { } else {
return `if($event.keyCode!=${code})return;` return `if($event.keyCode!==${code})return;`
} }
} }

View File

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

View File

@ -10,7 +10,17 @@ import { set, del } from '../observer/index'
import builtInComponents from '../components/index' import builtInComponents from '../components/index'
export function initGlobalAPI (Vue: GlobalAPI) { 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.util = util
Vue.set = set Vue.set = set
Vue.delete = del Vue.delete = del

View File

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

View File

@ -126,6 +126,19 @@ describe('Directive v-on', () => {
expect(spy).toHaveBeenCalled() 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', () => { it('should bind to a child component', () => {
Vue.component('bar', { Vue.component('bar', {
template: '<span>Hello</span>' template: '<span>Hello</span>'

View File

@ -1,6 +1,13 @@
import Vue from 'vue' import Vue from 'vue'
describe('Global config', () => { 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', () => { describe('silent', () => {
it('should be false by default', () => { it('should be false by default', () => {
Vue.util.warn('foo') Vue.util.warn('foo')

View File

@ -216,17 +216,22 @@ describe('codegen', () => {
it('generate events with keycode', () => { it('generate events with keycode', () => {
assertCodegen( assertCodegen(
'<input @input.enter="onInput">', '<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) // multiple keycodes (delete)
assertCodegen( assertCodegen(
'<input @input.delete="onInput">', '<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 // number keycode
assertCodegen( assertCodegen(
'<input @input.13="onInput">', '<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)}}}))}`
) )
}) })