Vue v-model 指令


示例

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

<template>
  <h1>v-model Example</h1>
  <p>写一些东西,然后会看到"inputValue"数据属性自动更新。</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 用于组件时,我们可以使用 get()set() 方法的计算属性,而不是使用 Vue 实例数据属性。 (参见示例 4

可以使用 v-model: 设置与默认的"modelValue"和"update:modelValue"不同的 props 和 Emit 名称。 (参见示例 5

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


修饰符

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


更多示例

示例 1

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

<template>
  <h1>v-model Example</h1>
  <p>拖动滑块更改"inputValue"数据属性,并看到输入文本字段由于 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

在具有 propsemits 的组件上使用 v-model ,以便 <input> 元素中的更改更新父级的"text"属性。

App.vue:

<template>
  <h2>v-model 指令示例</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>组件</h3>
    <p>在下面的文本输入字段中写入一些内容,以查看此处的更改是从组件发出的,并且父"text"属性通过使用 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>v-model 指令示例</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>组件</h3>
    <p>Two-way binding on component with v-model:</p>
    <ol>
      <li>该组件可以更新'text'属性(使用文本字段)。</li>
      <li>当"text"属性更改(使用按钮)时,组件会更新。</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

通过组件内的 get()set() 函数将 v-model 与计算值结合使用。

CompOne.vue:

<template>
  <div>
    <h3>组件</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 将默认 props 名称"modelValue"重命名为"message"。

App.vue:

<template>
  <h2>v-model 指令示例</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>组件</h3>
    <p>组件与 v-model 的双向绑定:</p>
    <ol>
      <li>该组件可以更新'text'属性(使用文本字段)。</li>
      <li>当"text"属性更改(使用按钮)时,组件会更新。</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>v-model 指令示例</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>组件</h3>
    <p>两个输入通过 props 与 v-model 绑定到组件并发出。</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>使用".lazy"修饰符,您必须先编写一些内容,然后单击其他位置,或者使用 Tab 键将焦点从输入元素上切换,然后才能更新属性。</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>v-model 指令示例</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>组件</h3>
    <p>在下面的文本输入字段中写一些内容。 单击其他位置或使用 Tab 键将焦点从输入元素移开,以查看自定义"allCapital"修饰符的效果。</p>
    <input 
      :value="modelValue" 
      @change="this.emitVal" 
    />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      // modelModifiers 最初是一个空对象。
      // 组件上设置的修饰符将存储在这里。
      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 Props 选项

Vue 教程:Vue $emit() 方法

Vue 教程:Vue Computed 计算属性

Vue 参考:Vue $emit() 方法

Vue 参考:Vue $props 对象

JavaScript 教程:JavaScript 对象访问器