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
时,必须使用 props
和 emits
正确设置组件接口才能实现双向绑定。
双向绑定 在组件上使用 v-model
的工作原理如下
- 当 Vue 检测到父实例属性发生变化时,新值将作为属性发送到组件。
- 当 Vue 检测到子组件发生变化时,新值将作为发射事件发送到父组件。
当在组件上使用 v-model
时,默认属性名称为 'modelValue',默认发射事件名称为 'update:modelValue'。(参见 示例 2 和 示例 3)。
当在组件上使用 v-model
时,我们可以使用具有 get()
和 set()
方法的计算属性,而不是使用 Vue 实例数据属性。(参见示例 4)
可以使用 v-model:
设置与默认 'modelValue' 和 'update:modelValue' 不同的属性和发射事件名称。(参见示例 5)
要将多个值连接到组件作为双向绑定,我们必须使用自己的 v-model
定义每个值。(参见示例 6)
修饰符
修饰符 | 细节 |
---|---|
.lazy |
Vue 使用 change 事件而不是 input 事件来同步。这意味着用户必须先修改输入,然后将焦点从输入元素移开,才能更新实例属性值。(参见示例 7) |
.number |
将输入类型转换为数字。使用 <input type="number"> 时会自动完成此操作。 |
.trim |
移除输入开始和结束处的空格。(参见示例 8) |
自定义 | 要为 v-model 创建自定义修饰符,我们首先需要定义一个名为 'modelModifiers' 的属性来存储新修饰符。修饰符功能写在方法中。如果设置了修饰符,则在将值发射回父组件之前,相应的代码会在方法中运行。(参见示例 9) |
更多示例
示例 1
使用滑块 (<input type="range">
) 来更改 'inputValue' 属性值。 <input type="text">
元素会自动更新,因为它使用 v-model
绑定到 'inputValue' 属性。
<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
,并使用 props
和 emits
,以便 <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
在组件内使用 get()
和 set()
函数与计算值一起使用 v-model
。
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 对象访问器