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 檢測到父例項屬性發生變化時,新值將作為 prop 傳送到元件。
- 當 Vue 檢測到子元件發生變化時,新值將作為一個 emit 事件向上傳送到父元件。
當 v-model
用於元件時,預設 prop 名稱是 'modelValue',預設 emit 事件名稱是 'update:modelValue'。(參見 示例 2 和 示例 3。)
當 v-model
用於元件時,我們不必使用 Vue 例項資料屬性,而是可以使用計算屬性,並帶有 get()
和 set()
方法。(參見示例 4)
與預設的 'modelValue' 和 'update:modelValue' 不同的 prop 和 emit 名稱,可以使用 v-model:
進行設定。(參見示例 5)
要將多個值作為雙向繫結連線到元件,我們必須為每個這樣的值定義自己的 v-model
。(參見示例 6)
修飾符
修飾符 | 詳情 |
---|---|
.lazy |
Vue 使用 change 事件而不是 input 事件來進行同步。這意味著使用者必須先修改輸入,然後將焦點從輸入元素移開,例項屬性的值才會更新。(參見示例 7) |
.number |
將輸入轉換為數字。使用 <input type="number"> 時會自動進行此操作。 |
.trim |
刪除輸入開頭和結尾的空白字元。(參見示例 8) |
custom | 要建立一個自定義的 v-model 修飾符,我們首先需要定義一個名為 'modelModifiers' 的 prop 來儲存新的修飾符。修飾符功能寫在一個方法中。如果設定了修飾符,則在將值 emit 回父元件之前,會在方法中執行相應的程式碼。(參見示例 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
在元件內部使用 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
將預設 prop 名稱 '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 Components
Vue 教程:Vue Props
Vue 教程:Vue $emit() Method
Vue 教程:Vue Computed Properties
Vue Reference: Vue $emit() Method
Vue Reference: Vue $props Object
JavaScript Tutorial: JavaScript Object Accessors