Vue3 component 大進化
https://vuejs.org/guide/components/v-model.html
v-model on a component can also accept an argument:
template
<MyComponent v-model:title="bookTitle" />
In the child component, we can support the corresponding argument by passing a string to defineModel() as its first argument:
vue
<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>
<template>
<input type="text" v-model="title" />
</template>
If prop options are also needed, they should be passed after the model name:
const title = defineModel('title', { required: true })
基本用法
v-model 可以在元件上使用來實現雙向綁定。
從 Vue 3.4 開始,建議的方法是使用 defineModel() 巨集:
vue 視圖
<!-- Child.vue -->
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>Parent bound v-model is: {{ model }}</div>
</template>
然後父級可以用 v-model 綁定一個值:
template
<!-- Parent.vue -->
<Child v-model="countModel" />
defineModel() 傳回的值是一個引用。它可以像任何其他引用一樣被存取和改變,除了它充當父值和本地值之間的雙向綁定:
.value與父級v-model綁定的值同步;- 當它被子進程改變時,它也會導致父進程的綁定值被更新。
usage:這表示您也可以使用 v-model 將此引用綁定到本機輸入元素,從而可以直接包裝本機輸入元素,同時提供相同的 v-model 用法:
vue 視圖
<script setup>
const model = defineModel()
</script>
<template>
<input v-model="model" />
</template>
引擎蓋下
defineModel 是一個方便 的巨集。編譯器將其擴展為以下內容:
- 名為
modelValue的 prop,與本地引用的值同步; - 名為
update:modelValue的事件,當本地引用的值發生變化時會發出該事件。
vue 視圖
<!-- Child.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
然後,父元件中的 v-model="modelValue" 將被編譯為:
template
<!-- Parent.vue -->
<Child
:modelValue="foo"
@update:modelValue="$event => (foo = $event)"
/>
正如您所看到的,它更加冗長。然而,了解幕後發生的事情是有幫助的。
由於 defineModel 聲明了一個 prop,因此您可以透過將其傳遞給 defineModel 來聲明底層 prop 的選項:
// making the v-model required
const model = defineModel({ required: true })
// providing a default value
const model = defineModel({ default: 0 })
WARNING 警告 If you have a
defaultvalue fordefineModelprop and you don't provide any value for this prop from the parent component, it can cause a de-synchronization between parent and child components. In the example below, the parent'smyRefis undefined, but the child'smodelis 1:如果defineModel屬性有一個default值,且您沒有從父元件為此屬性提供任何值,則可能會導致父元件和子元 件之間不同步。在下面的範例中,父級的myRef未定義,但子級的model為 1:
// child component:
const model = defineModel({ default: 1 })
// parent component:
const myRef = ref()
html
<Child v-model="myRef"></Child>
v-model arguments
組件上的 v-model 也可以接受參數:
template
<MyComponent v-model:title="bookTitle" />
在子元件中,我們可以透過將字串傳遞給 defineModel() 作為其第一個參數來支援對應的參數:
vue 視圖
<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>
<template>
<input type="text" v-model="title" />
</template>
Try it in the Playground 在遊樂場嘗試一下
如果還需要 prop 選項,則應在模型名稱之後傳遞它們:
const title = defineModel('title', { required: true })
Multiple v-model bindings
透過利用我們先前透過 v-model 參數學習的針對特定道具和事件的能力,我們現在可以在單一元件實例上建立多個 v-model 綁定。
每個 v-model 將同步到不同的 prop,而不需 要在元件中使用額外的選項:
template
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
vue 視圖
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>
<template>
<input type="text" v-model="firstName" />
<input type="text" v-model="lastName" />
</template>
Try it in the Playground 在遊樂場嘗試一下
Handling v-model modifiers
When we were learning about form input bindings, we saw that v-model has built-in modifiers - .trim, .number and .lazy. In some cases, you might also want the v-model on your custom input component to support custom modifiers.當我們學習表單輸入綁定時,我們看到 v-model 有內建修飾符 - .trim、.number 和 .lazy。在某些情況下,您可能還想自訂輸入元件上的 v-model 支援自訂修飾符。
Let's create an example custom modifier, capitalize, that capitalizes the first letter of the string provided by the v-model binding:讓我們建立一個範例自訂修飾符 capitalize,它將 v-model 綁定提供的字串的第一個字母大寫:
template 範本
<MyComponent v-model.capitalize="myText" />
Modifiers added to a component v-model can be accessed in the child component by destructuring the defineModel() return value like this:新增至元件 v-model 的修飾符可以透過解構 defineModel() 傳回值在子元件中訪問,如下所示:
vue 視圖
<script setup>
const [model, modifiers] = defineModel()
console.log(modifiers) // { capitalize: true }
</script>
<template>
<input type="text" v-model="model" />
</template>
To conditionally adjust how the value should be read / written based on modifiers, we can pass get and set options to defineModel(). These two options receive the value on get / set of the model ref and should return a transformed value. This is how we can use the set option to implement the capitalize modifier:要根據修飾符有條件地調整值的讀取/寫入方式,我們可以將 get 和 set 選項傳遞給 defineModel()。這兩個選項接收模型所引用的 get/set 值,並應傳回轉換後的值。這就是我們如何使用 set 選項來實作 capitalize 修飾符:
vue 視圖
<script setup>
const [model, modifiers] = defineModel({
set(value) {
if (modifiers.capitalize) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
return value
}
})
</script>
<template>
<input type="text" v-model="model" />
</template>
Try it in the Playground 在遊樂場嘗試一下
Modifiers for v-model with arguments
Here's another example of using modifiers with multiple v-model with different arguments:這是使用具有不同參數的多個 v-model 修飾符的另一個範例:
template 範本
<UserName
v-model:first-name.capitalize="first"
v-model:last-name.uppercase="last"
/>
vue 視圖
<script setup>
const [firstName, firstNameModifiers] = defineModel('firstName')
const [lastName, lastNameModifiers] = defineModel('lastName')
console.log(firstNameModifiers) // { capitalize: true }
console.log(lastNameModifiers) // { uppercase: true }
</script>