Selaa lähdekoodia

fix: fix v-model :value warning on custom component

fix #7084
Evan You 8 vuotta sitten
vanhempi
commit
59dea37403

+ 13 - 15
src/platforms/web/compiler/directives/model.js

@@ -21,7 +21,6 @@ export default function model (
   const modifiers = dir.modifiers
   const tag = el.tag
   const type = el.attrsMap.type
-  const attrsMap = el.attrsMap
 
   if (process.env.NODE_ENV !== 'production') {
     // inputs with type="file" are read only and setting the input's
@@ -32,20 +31,6 @@ export default function model (
         `File inputs are read only. Use a v-on:change listener instead.`
       )
     }
-
-    // warn if v-bind:value conflicts with v-model
-    if (
-      (attrsMap['v-bind:value'] || attrsMap[':value']) &&
-      type !== 'checkbox' &&
-      type !== 'radio' &&
-      tag !== 'select'
-    ) {
-      const vBindValue = attrsMap['v-bind:value'] ? 'v-bind:value' : ':value'
-      warn(
-        `${vBindValue} conflicts with v-model on the same element ` +
-        'because the latter already expands to a value binding internally'
-      )
-    }
   }
 
   if (el.component) {
@@ -143,6 +128,19 @@ function genDefaultModel (
   modifiers: ?ASTModifiers
 ): ?boolean {
   const type = el.attrsMap.type
+
+  // warn if v-bind:value conflicts with v-model
+  if (process.env.NODE_ENV !== 'production') {
+    const value = el.attrsMap['v-bind:value'] || el.attrsMap[':value']
+    if (value) {
+      const binding = el.attrsMap['v-bind:value'] ? 'v-bind:value' : ':value'
+      warn(
+        `${binding}="${value}" conflicts with v-model on the same element ` +
+        'because the latter already expands to a value binding internally'
+      )
+    }
+  }
+
   const { lazy, number, trim } = modifiers || {}
   const needCompositionGuard = !lazy && type !== 'range'
   const event = lazy

+ 25 - 10
test/unit/features/directives/model-text.spec.js

@@ -255,12 +255,9 @@ describe('Directive v-model text', () => {
       data: {
         test: 'foo'
       },
-      template: '<input type="text" v-model="test" v-bind:value="test"/>'
+      template: '<input type="text" v-model="test" v-bind:value="test">'
     }).$mount()
-    expect(
-      'v-bind:value conflicts with v-model on the same element because the latter already ' +
-      'expands to a value binding internally'
-    ).toHaveBeenWarned()
+    expect('v-bind:value="test" conflicts with v-model').toHaveBeenWarned()
   })
 
   it('warn if v-model and :value conflict', () => {
@@ -268,12 +265,30 @@ describe('Directive v-model text', () => {
       data: {
         test: 'foo'
       },
-      template: '<input type="text" v-model="test" :value="test"/>'
+      template: '<input type="text" v-model="test" :value="test">'
     }).$mount()
-    expect(
-      ':value conflicts with v-model on the same element because the latter already ' +
-      'expands to a value binding internally'
-    ).toHaveBeenWarned()
+    expect(':value="test" conflicts with v-model').toHaveBeenWarned()
+  })
+
+  it('should not warn on radio, checkbox, or custom component', () => {
+    new Vue({
+      data: { test: '' },
+      components: {
+        foo: {
+          props: ['model', 'value'],
+          model: { prop: 'model', event: 'change' },
+          template: `<div/>`
+        }
+      },
+      template: `
+        <div>
+          <input type="checkbox" v-model="test" :value="test">
+          <input type="radio" v-model="test" :value="test">
+          <foo v-model="test" :value="test"/>
+        </div>
+      `
+    }).$mount()
+    expect('conflicts with v-model').not.toHaveBeenWarned()
   })
 
   if (!isAndroid) {