diff --git a/flow/compiler.js b/flow/compiler.js index ad09a2e2ebe..d8decc7b5df 100644 --- a/flow/compiler.js +++ b/flow/compiler.js @@ -163,6 +163,7 @@ declare type ASTElement = { value: string; callback: string; expression: string; + lazy: boolean; }; directives?: Array; diff --git a/flow/vnode.js b/flow/vnode.js index c9f3b3887d3..4ecf686b8c1 100644 --- a/flow/vnode.js +++ b/flow/vnode.js @@ -62,6 +62,7 @@ declare interface VNodeData { model?: { value: any; callback: Function; + lazy: boolean; }; }; diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js index c96b3a38511..c95d896d96b 100644 --- a/src/compiler/codegen/index.js +++ b/src/compiler/codegen/index.js @@ -279,8 +279,15 @@ export function genData (el: ASTElement, state: CodegenState): string { el.model.callback },expression:${ el.model.expression - }},` + }` + + if (el.model.lazy) { + data += `,lazy:true` + } + + data += '}' } + // inline-template if (el.inlineTemplate) { const inlineTemplate = genInlineTemplate(el, state) diff --git a/src/compiler/directives/model.js b/src/compiler/directives/model.js index c7a4c09b574..eb6c106b2b4 100644 --- a/src/compiler/directives/model.js +++ b/src/compiler/directives/model.js @@ -8,7 +8,7 @@ export function genComponentModel ( value: string, modifiers: ?ASTModifiers ): ?boolean { - const { number, trim } = modifiers || {} + const { number, trim, lazy } = modifiers || {} const baseValueExpression = '$$v' let valueExpression = baseValueExpression @@ -26,6 +26,7 @@ export function genComponentModel ( el.model = { value: `(${value})`, expression: JSON.stringify(value), + lazy: !!lazy, callback: `function (${baseValueExpression}) {${assignment}}` } } diff --git a/src/core/vdom/create-component.js b/src/core/vdom/create-component.js index 380902000df..633d0b078e8 100644 --- a/src/core/vdom/create-component.js +++ b/src/core/vdom/create-component.js @@ -251,7 +251,9 @@ function mergeHook (f1: any, f2: any): Function { // prop and event handler respectively. function transformModel (options, data: any) { const prop = (options.model && options.model.prop) || 'value' - const event = (options.model && options.model.event) || 'input' + const defaultEvent = data.model.lazy ? 'change' : 'input' + const event = (options.model && (data.model.lazy ? + options.model.eventLazy : options.model.event)) || defaultEvent ;(data.attrs || (data.attrs = {}))[prop] = data.model.value const on = data.on || (data.on = {}) const existing = on[event] diff --git a/test/unit/features/directives/model-component.spec.js b/test/unit/features/directives/model-component.spec.js index 49ff4ddb138..7e819f21d24 100644 --- a/test/unit/features/directives/model-component.spec.js +++ b/test/unit/features/directives/model-component.spec.js @@ -149,6 +149,40 @@ describe('Directive v-model component', () => { expect(vm.text).toBe('foo o') }) + it('modifier: .lazy', () => { + const vm = new Vue({ + template: ` +
+ + +
+ `, + data: { text1: 'foo', text2: 'foo' }, + components: { + 'default-model': { + template: '' + }, + 'custom-model': { + template: '', + model: { + eventLazy: 'lazy-update' + } + } + } + }).$mount() + expect(vm.text1).toBe('foo') + vm.$refs.default.$emit('input', 'bar') + expect(vm.text1).toBe('foo') + vm.$refs.default.$emit('change', 'baz') + expect(vm.text1).toBe('baz') + + // customized model option + vm.$refs.custom.$emit('change', 'bar') + expect(vm.text2).toBe('foo') + vm.$refs.custom.$emit('lazy-update', 'baz') + expect(vm.text2).toBe('baz') + }) + // #8436 it('should not double transform mode props', () => { const BaseInput = { diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index d7faa204944..35ca76acd27 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -170,6 +170,12 @@ describe('codegen', () => { '', `with(this){return _c('my-component',{model:{value:(\n test \n),callback:function ($$v) {\n test \n=$$v},expression:"\\n test \\n"}})}` ) + + // for lazy modifier + assertCodegen( + '', + `with(this){return _c('my-component',{model:{value:(\n test \n),callback:function ($$v) {\n test \n=$$v},expression:"\\n test \\n",lazy:true}})}` + ) }) it('generate template tag', () => { diff --git a/types/options.d.ts b/types/options.d.ts index 323c7630986..c499d406b9c 100644 --- a/types/options.d.ts +++ b/types/options.d.ts @@ -109,6 +109,7 @@ export interface ComponentOptions< model?: { prop?: string; event?: string; + eventLazy?: string; }; parent?: Vue; @@ -127,6 +128,7 @@ export interface FunctionalComponentOptions