Vue v-model 指令


示例

使用v-model指令创建一个双向绑定<input>元素和数据属性。

<template>
  <h1>v-model Example</h1>
  <p>Write something, and see the 'inputValue' data property update automatically.</p>
  <input type="text" v-model="inputValue"> 
  <p>inputValue property: "{{ inputValue }}"</p>
</template>
运行示例 »

请参阅下面的更多示例。


定义和用法

这个v-model指令用于在表单输入元素之间或 Vue 实例属性和组件之间创建双向绑定。


表单输入元素v-model

可以使用的表单输入元素v-model<input>,<select><textarea>

双向绑定v-model表单输入元素的工作方式如下:

  • 当Vue检测到输入值发生变化时,它会相应地更新相应的数据属性。 (HTML -> JavaScript)
  • 当 Vue 检测到 Vue 实例属性发生变化时,它会相应地更新相应的输入值。 (JavaScript -> HTML)

(参见上面的示例和下面的示例 1。)


组件具有v-model

什么时候v-model用于组件,组件接口必须正确设置propsemits从而实现双向绑定。

双向绑定v-model在组件上的工作方式如下:

  • 当 Vue 检测到父实例属性发生更改时,新值将作为 prop 发送到组件。
  • 当 Vue 检测到子组件中的更改时,新值将作为发出事件发送到父组件。

什么时候v-model用于组件,默认 prop 名称为“modelValue”,默认发出事件名称为“update:modelValue”。 (看示例2示例3.)

什么时候v-model在组件上使用,我们可以使用计算属性,而不是使用 Vue 实例数据属性get()set()方法。 (参见示例4

可以使用以下命令设置与默认“modelValue”和“update:modelValue”不同的 props 和 Emits 名称v-model:。 (参见示例5

要让多个值作为双向绑定连接到组件,我们必须用自己的值定义每个这样的值v-model。 (参见示例6


修饰符

修饰符 细节
.lazy 这个changeVue 使用事件而不是input何时同步的事件。这意味着用户必须首先修改输入,然后在更新实例属性值之前将焦点从输入元素移开。 (参见示例7
.number 将输入类型转换为数字。这是在使用时自动完成的<input type="number">
.trim 删除输入开头和结尾的空格。 (参见示例8
风俗 创建自定义修饰符v-model,我们首先需要定义一个 prop 'modelModifiers' 来存储新的修饰符。修饰符功能写在方法中。如果设置了修饰符,则在将值发送回父组件之前,会在方法中运行适当的代码。 (参见示例9


更多示例

示例1

使用滑块 (<input type="range">) 更改“inputValue”属性值。这<input type="text">元素会自动更新,因为它绑定到 'inputValue' 属性v-model

<template>
  <h1>v-model Example</h1>
  <p>Drag the slider to change the 'inputValue' data property, and see the input text field update automatically because of the two-way binding from v-model.</p>
  <input type="range" min="-50" max="50" v-on:input="sliderChange" value="4">
  <p>inputValue property: "{{ inputValue }}"</p>
  <input type="text" v-model="inputValue"> 
</template>

<script>
export default {
  data() {
    return {
      inputValue: null
    };
  },
  methods: {
    sliderChange(evt) {
      this.inputValue = evt.target.value
    }
  }
}
</script>
运行示例 »

示例2

使用v-model在组件上propsemits从而使变化<input>元素更新父级的“text”属性。

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "{{ text }}"</p>
  <comp-one v-model="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: 'Say Cheese'
    }
  }
}
</script>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Write something in the text input field below to see that changes here are emitted from the component, and the parent 'text' property gets updated by the use of v-model.</p>
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    />
  </div>
</template>

<script>
  export default {
    props: ['modelValue'],
    emits: ['update:modelValue']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 500px;
}
</style>
运行示例 »

示例3

使用v-model在组件上更清楚地演示双向绑定。组件可以更新父“text”属性,并且当父“text”属性更改时组件也会更新。

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "<pre>{{ text }}</pre>"</p>
  <button v-on:click="this.text = 'Hello!'">text='Hello!'</button>
  <comp-one v-model="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: 'Say Cheese'
    }
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: yellow;
}
</style>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two-way binding on component with v-model:</p>
    <ol>
      <li>The component can update the 'text' property (using text field).</li>
      <li>The component gets updated when the 'text' property is changed (using button).</li>
    </ol>
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    />
  </div>
</template>

<script>
  export default {
    props: ['modelValue'],
    emits: ['update:modelValue']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 600px;
}
</style>
运行示例 »

示例4

使用v-model与计算值get()set()组件内部的函数。

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two-way binding on component with v-model:</p>
    <ol>
      <li>The component can update the 'text' property (using text field).</li>
      <li>The component gets updated when the 'text' property is changed (using button).</li>
    </ol>
    <input v-model="inpVal"/>
  </div>
</template>

<script>
  export default {
    props: ['modelValue'],
    emits: ['update:modelValue'],
    computed: {
      inpVal: {
        get() {
          return this.modelValue;
        },
        set(inpVal) {
          this.$emit('update:modelValue',inpVal)
        }
      }
    }
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 600px;
}
</style>
运行示例 »

示例5

使用v-model:message在组件上将默认道具名称“modelValue”重命名为“message”。

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "<pre>{{ text }}</pre>"</p>
  <button v-on:click="this.text = 'Hello!'">text='Hello!'</button>
  <comp-one v-model:message="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: 'Say Cheese'
    }
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: yellow;
}
</style>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two-way binding on component with v-model:</p>
    <ol>
      <li>The component can update the 'text' property (using text field).</li>
      <li>The component gets updated when the 'text' property is changed (using button).</li>
    </ol>
    <input
      :value="message"
      @input="$emit('update:message', $event.target.value)"
    />
  </div>
</template>

<script>
  export default {
    props: ['message'],
    emits: ['update:message']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 600px;
}
</style>
运行示例 »

示例6

使用v-model在组件上两次以创建具有两个值的双向绑定。

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>Name: "<pre>{{ name }}</pre>"</p>
  <p>Height: <pre>{{ height }}</pre> cm</p>
  <comp-one 
    v-model:name="name"
    v-model:height="height"
  />
</template>

<script>
export default {
  data() {
    return {
      name: 'Olaf',
      height: 120
    }
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: yellow;
}
</style>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two inputs are bound to the component with v-model through props and emits.</p>
    <p>
      <label>
        Name: 
        <input
          type="text"
          :value="name"
          @input="$emit('update:name', $event.target.value)"
        />
      </label>
    </p>
    <p>
      <label>
        Height:
        <input
          type="range"
          :value="height"
          @input="$emit('update:height', $event.target.value)"
          min="50"
          max="200"
        />
        {{ this.$props.height }} cm
      </label>
    </p>
  </div>
</template>

<script>
  export default {
    props: ['name','height'],
    emits: ['update:name','update:height']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 300px;
}
</style>
运行示例 »

示例7

使用.lazy这样用户必须首先修改输入元素,然后在属性更新之前将焦点从输入元素上移开v-model

<template>
  <h1>v-model Example</h1>
  <p>Using the '.lazy' modifier, you must first write something, then click somewhere else, or use the tab key to switch focus away from the input element, before the property get updated.</p>
  <input type="text" v-model.lazy="inputValue"> 
  <p>inputValue property: "{{ inputValue }}"</p>
</template>

<script>
export default {
  data() {
    return {
      inputValue: null
    };
  }
}
</script>
运行示例 »

示例8

使用.lazy这样用户必须首先修改输入元素,然后在属性更新之前将焦点从输入元素上移开v-model

<template>
  <h1>v-model Example</h1>
  <p>Using the '.trim' modifier will remove any white spaces at the start and end of the input.</p>
  <p>Add white spaces at the start and end in the input fields below to see the difference with or with out '.trim'.</p>
  <p>No '.trim': <input type="text" v-model="inputVal1"> "<pre>{{ inputVal1 }}</pre>"</p> 
  <p>With '.trim': <input type="text" v-model.trim="inputVal2"> "<pre>{{ inputVal2 }}</pre>"</p>
  
</template>

<script>
export default {
  data() {
    return {
      inputVal1: 'Hello',
      inputVal2: 'Hi'
    };
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: lightgreen;

}
</style>
运行示例 »

示例9

使用自定义.allCapital修饰符将输入中的所有字符转换为大写,如果.allCapital修改器已设置。

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "{{ text }}"</p>
  <comp-one v-model.allCapital="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: ''
    }
  }
}
</script>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Write something in the text input field below. Click somewhere else or use the tab key to shift focus away from the input element to see the effect of the custom 'allCapital' modifier.</p>
    <input 
      :value="modelValue" 
      @change="this.emitVal" 
    />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      // modelModifiers is an empty object initially.
      // Modifiers set on the component will be stored here.
      default: () => ({}) 
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitVal(e) {
      let value = e.target.value
      if (this.modelModifiers.allCapital) {
        value = value.toUpperCase()
      }
      this.$emit('update:modelValue', value)
    }
  }
}
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 500px;
}
</style>
运行示例 »

相关页面

Vue教程:Vue 组件

Vue教程:Vue 道具

Vue教程:Vue $emit() 方法

Vue教程:Vue 计算属性

Vue参考:Vue $emit() 方法

Vue参考:Vue $props 对象

JavaScript 教程:JavaScript 对象访问器