概覽
就變化內容而言,此部分屬于高階內容:
- 非兼容:用于自定義組件時,
v-model的
?prop 和事件默認名稱已更改:- prop:
value
?->?modelValue
; - event:
input
?->?update:modelValue
;
- prop:
- 非兼容:
v-bind
?的?.sync
?修飾符和組件的?model
?選項已移除,可用?v-model
?作為代替; - 新增:現在可以在同一個組件上使用多個?
v-model
?進行雙向綁定; - 新增:現在可以自定義?
v-model
?修飾符。
在 Vue 2.2 中,我們引入了?model
?組件選項,允許組件自定義用于?v-model
?的 prop 和事件。但是,這仍然只允許在組件上使用一個?model
。
在 Vue 3 中,雙向數據綁定的 API 已經標準化,減少了開發者在使用?v-model
?指令時的混淆并且在使用?v-model
?指令時可以更加靈活。
2.x 語法
在 2.x 中,在組件上使用?v-model
?相當于綁定?value
?prop 和?input
?事件:
<ChildComponent v-model="pageTitle" /><!-- 是以下的簡寫: --><ChildComponent :value="pageTitle" @input="pageTitle = $event" />
如果要將屬性或事件名稱更改為其他名稱,則需要在?ChildComponent
?組件中添加?model
?選項:
<!-- ParentComponent.vue --><ChildComponent v-model="pageTitle" />
// ChildComponent.vueexport default {model: {prop: 'title',event: 'change'},props: {// 這將允許 `value` 屬性用于其他用途value: String,// 使用 `title` 代替 `value` 作為 model 的 proptitle: {type: String,default: 'Default title'}}
}
所以,在這個例子中?v-model
?是以下的簡寫:
<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
使用?v-bind.sync
在某些情況下,我們可能需要對某一個 prop 進行“雙向綁定”(除了前面用?v-model
?綁定 prop 的情況)。為此,我們建議使用?update:myPropName
?拋出事件。例如,對于在上一個示例中帶有?title
?prop 的?ChildComponent
,我們可以通過下面的方式將分配新 value 的意圖傳達給父級:
this.$emit('update:title', newValue)
如果需要的話,父級可以監聽該事件并更新本地 data property。例如:
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
為了方便起見,我們可以使用?.sync
?修飾符來縮寫,如下所示:
<ChildComponent :title.sync="pageTitle" />
3.x 語法
在 3.x 中,自定義組件上的?v-model
?相當于傳遞了?modelValue
?prop 并接收拋出的?update:modelValue
?事件:
<ChildComponent v-model="pageTitle" /><!-- 是以下的簡寫: --><ChildComponent:modelValue="pageTitle"@update:modelValue="pageTitle = $event"
/>
v-model
?參數
若需要更改?model
?名稱,作為組件內?model
?選項的替代,現在我們可以將一個?argument?傳遞給?v-model
:
<ChildComponent v-model:title="pageTitle" /><!-- 是以下的簡寫: --><ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
這也可以作為?.sync
?修飾符的替代,而且允許我們在自定義組件上使用多個?v-model
。
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" /><!-- 是以下的簡寫: --><ChildComponent:title="pageTitle"@update:title="pageTitle = $event":content="pageContent"@update:content="pageContent = $event"
/>
v-model
?修飾符
除了像?.trim
?這樣的 2.x 硬編碼的?v-model
?修飾符外,現在 3.x 還支持自定義修飾符:
<div id="app"><my-component v-model.capitalize="myText"></my-component>{{ myText }}
</div>
讓我們創建一個示例自定義修飾符?capitalize
,它將?v-model
?綁定提供的字符串的第一個字母大寫。
app.component('my-component', {props: {modelValue: String,modelModifiers: {default: () => ({})}},emits: ['update:modelValue'],template: `<input type="text":value="modelValue"@input="$emit('update:modelValue', $event.target.value)">`,created() {console.log(this.modelModifiers) // { capitalize: true }}
})
添加到組件?v-model
?的修飾符將通過?modelModifiers
?prop 提供給組件。在下面的示例中,我們創建了一個組件,其中包含默認為空對象的?modelModifiers
?prop。
請注意,當組件的?created
?生命周期鉤子觸發時,modelModifiers
?prop 會包含?capitalize
,且其值為?true
——因為?capitalize
?被設置在了寫為?v-model.capitalize="myText"
?的?v-model
?綁定上。
現在我們已經設置了 prop,我們可以檢查?modelModifiers
?對象鍵并編寫一個處理器來更改發出的值。在下面的代碼中,每當?<input/>
?元素觸發?input
?事件時,我們都將字符串大寫。
<div id="app"><my-component v-model.capitalize="myText"></my-component>{{ myText }}
</div>
const app = Vue.createApp({data() {return {myText: ''}}
})app.component('my-component', {props: {modelValue: String,modelModifiers: {default: () => ({})}},emits: ['update:modelValue'],methods: {emitValue(e) {let value = e.target.valueif (this.modelModifiers.capitalize) {value = value.charAt(0).toUpperCase() + value.slice(1)}this.$emit('update:modelValue', value)}},template: `<inputtype="text":value="modelValue"@input="emitValue">`
})app.mount('#app')
對于帶參數的?v-model
?綁定,生成的 prop 名稱將為?arg + "Modifiers"
:
<my-component v-model:description.capitalize="myText"></my-component>
app.component('my-component', {props: ['description', 'descriptionModifiers'],emits: ['update:description'],template: `<input type="text":value="description"@input="$emit('update:description', $event.target.value)">`,created() {console.log(this.descriptionModifiers) // { capitalize: true }}
})
遷移策略
我們推薦:
-
檢查你的代碼庫中所有使用?
.sync
?的部分并將其替換為?v-model
:
<ChildComponent :title.sync="pageTitle" /><!-- 替換為 --><ChildComponent v-model:title="pageTitle" />
-
對于所有不帶參數的?
v-model
,請確保分別將 prop 和 event 命名更改為?modelValue
?和?update:modelValue
<ChildComponent v-model="pageTitle" />
// ChildComponent.vueexport default {props: {modelValue: String // 以前是`value:String`},emits: ['update:modelValue'],methods: {changePageTitle(title) {// 以前是 `this.$emit('input', title)`this.$emit('update:modelValue', title) }}
}