Ana içeriğe geç

Bileşen v-model

Bileşen v-model

Temel Kullanım

v-model, bir bileşende iki yönlü veri bağlama uygulamak için kullanılabilir.

Vue 3.4 ile birlikte, bunu gerçekleştirmek için önerilen yaklaşım, defineModel() makrosunu kullanmaktır:

<!-- Child.vue -->
<script setup>
const model = defineModel()

function update() {
model.value++
}
</script>

<template>
<div>Üst bileşende bağlı v-model: {{ model }}</div>
<button @click="update">Arttır</button>
</template>

Üst bileşen, v-model ile bir değeri bağlayabilir:

<!-- Parent.vue -->
<Child v-model="countModel" />

defineModel() tarafından döndürülen değer bir ref'dir. Diğer ref'ler gibi erişilebilir ve değiştirilebilir, tek farkla ki bu, bir üst değer ile bir yerel değer arasında iki yönlü bir bağlama olarak işlev görür:

  • .value'sı, üst v-model ile bağlı olan değerle senkronizedir;
  • Çocuk tarafından değiştirildiğinde, üstte bağlı değer de güncellenir.

Bu, bu ref'i v-model ile bir yerel giriş elemanına da bağlayabileceğiniz anlamına gelir, bu da yerel giriş elemanlarını sarmayı ve aynı v-model kullanımını sağlamayı kolaylaştırır:

<script setup>
const model = defineModel()
</script>

<template>
<input v-model="model" />
</template>

Oyun alanında dene

Altta Ne Oluyor

defineModel, bir kolaylık makrosudur. Derleyici bunu aşağıdakilere genişletir:

  • Yerel ref'in değeriyle senkronize edilen modelValue adlı bir prop;
  • Yerel ref'in değeri değiştirildiğinde yayılacak olan update:modelValue adlı bir olay.

Aşağıdakileri önceden 3.4 öncesinde aynı çocuk bileşeni uygulamak için kullanabilirsiniz:

<!-- 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>

Sonrasında, üst bileşende v-model="foo" derlendiğinde:

<!-- Parent.vue -->
<Child
:modelValue="foo"
@update:modelValue="$event => (foo = $event)"
/>

Gördüğünüz gibi, oldukça daha ayrıntılı. Ancak, altında neler olup bittiğini anlamak için yararlıdır.

Çünkü defineModel bir prop ilan ettiği için, defineModel'a geçirerek temel prop'un seçeneklerini de belirleyebilirsiniz:

// v-model'i zorunlu kılma
const model = defineModel({ required: true })

// varsayılan bir değer sağlama
const model = defineModel({ default: 0 })
tehlike

Eğer defineModel prop'u için bir default değeri varsa ve üst bileşenden bu prop için herhangi bir değer sağlanmazsa, üst ve alt bileşenler arasında senkronizasyonun bozulmasına neden olabilir. Aşağıdaki örnekte, üstteki myRef tanımsız, ancak alt bileşenin model değeri 1'dir:

Alt bileşen:

const model = defineModel({ default: 1 })

Üst bileşen:

const myRef = ref()
<Child v-model="myRef"></Child>

Öncelikle, bir yerel elemanda v-model kullanımına yeniden göz atalım:

<input v-model="searchText" />

Altta, şablon derleyicisi v-model'i daha ayrıntılı bir eşdeğeri genişletir. Yani yukarıdaki kod, aşağıdaki gibi işler:

<input
:value="searchText"
@input="searchText = $event.target.value"
/>

Bir bileşende kullanıldığında, v-model bunun yerine buna genişler:

<CustomInput
:model-value="searchText"
@update:model-value="newValue => searchText = newValue"
/>

Bunun çalışması için, `` bileşeninin iki şeyi yapması gerekir:

  1. Yerel `elemanınınvalueözelliğinimodelValue` prop'una bağlamak
  2. Yerel bir input olayı tetiklendiğinde, yeni değerle update:modelValue özel olayını yaymak

İşte bu şekilde:

<!-- CustomInput.vue -->
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>

<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>

Artık v-model bu bileşenle mükemmel bir şekilde çalışmalıdır:

<CustomInput v-model="searchText" />

Oyun alanında dene

Bu bileşende v-model'i uygulamanın bir başka yolu, hem bir getter hem de bir setter ile yazılabilir bir computed özelliği kullanmaktır. get yöntemi modelValue özelliğini döndürmelidir ve set yöntemi ilgili olayı yaymalıdır:

<!-- CustomInput.vue -->
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
computed: {
value: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
}
}
</script>

<template>
<input v-model="value" />
</template>

v-model Argümanları

Bir bileşende v-model, bir argümanı da kabul edebilir:

<MyComponent v-model:title="bookTitle" />

Alt bileşende, ilgili argümanı karşılamak için defineModel()'a bir string geçerek destekleyebiliriz:

<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>

<template>
<input type="text" v-model="title" />
</template>

Oyun alanında dene

Eğer prop seçeneklerine de ihtiyaç varsa, bunları model isminin ardından geçirmelisiniz:

const title = defineModel('title', { required: true })

3.4 Öncesi Kullanım

<!-- MyComponent.vue -->
<script setup>
defineProps({
title: {
required: true
}
})
defineEmits(['update:title'])
</script>

<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>

Oyun alanında dene

Bu durumda, varsayılan modelValue prop'u ve update:modelValue olayı yerine, alt bileşen bir title prop'u beklemeli ve üst değeri güncellemek için update:title olayını yaymalıdır:

<!-- MyComponent.vue -->
<script>
export default {
props: ['title'],
emits: ['update:title']
}
</script>

<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>

Oyun alanında dene

Birden Fazla v-model Bağlantısı

v-model argümanlarıile öğrendiğimiz gibi, belirli bir prop ve olayı hedefleme yeteneğini kullanarak, tek bir bileşen örneğinde birden fazlav-model` bağlamamız mümkün.

Her v-model, bileşende fazladan seçenekler gerektirmeden farklı bir prop'a senkronize edilir:

<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
<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>

Oyun alanında dene

3.4 Öncesi Kullanım

<script setup>
defineProps({
firstName: String,
lastName: String
})

defineEmits(['update:firstName', 'update:lastName'])
</script>

<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>

Oyun alanında dene

<script>
export default {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName']
}
</script>

<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>

Oyun alanında dene

v-model Modifikasyonları ile İlgilenmek

Form giriş bağlamaları hakkında bilgi aldığımızda, v-model'in dahili modifikasyonları - .trim, .number ve .lazy - olduğunu gördük. Bazı durumlarda, özel bir girdi bileşeninizde v-model'in özel modifikasyonları desteklemesini de isteyebilirsiniz.

v-model bağlaması ile sağlanan string'in ilk harfini büyük hale getiren bir özel modifikasyon olan capitalize örneğini oluşturalım:

<MyComponent v-model.capitalize="myText" />

Bileşen v-model'ine eklenen modifikasyonlar, alt bileşende defineModel() dönüş değerini şu şekilde parçalayarak erişilebilir:

<script setup>
const [model, modifiers] = defineModel()

console.log(modifiers) // { capitalize: true }
</script>

<template>
<input type="text" v-model="model" />
</template>

Değerin, modifikasyonlara bağlı olarak nasıl okunacağını veya yazılacağını şartlı olarak ayarlamak için, defineModel()'a get ve set seçenekleri geçebiliriz. Bu iki seçenek, model ref'in elde edilmesi veya ayarlanması sırasında değeri alır ve dönüştürülmüş bir değer döndürmelidir. capitalize modifikasyonunu gerçekleştirmek içinset seçeneğini nasıl kullanabileceğimiz:

<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>

Oyun alanında dene

3.4 Öncesi Kullanım

<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { default: () => ({}) }
})

const emit = defineEmits(['update:modelValue'])

function emitValue(e) {
let value = e.target.value
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue', value)
}
</script>

<template>
<input type="text" :value="props.modelValue" @input="emitValue" />
</template>

Oyun alanında dene

Bileşene eklenen modifikasyonlar, bileşene modelModifiers prop'u ile sağlanır. Aşağıdaki örnekte, varsayılan olarak boş bir nesne dönen modelModifiers prop'una sahip bir bileşen oluşturduk:

<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
created() {
console.log(this.modelModifiers) // { capitalize: true }
}
}
</script>

<template>
<input
type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>

Bileşenin modelModifiers prop'unun capitalize içerdiğini ve değerinin true olduğunu unutmayın - bu, v-model bağlaması üzerinde v-model.capitalize="myText" olarak ayarlandığı içindir.

Artık prop'umuzu ayarladıktan sonra, modelModifiers nesnesi anahtarlarını kontrol edebilir ve yayılan değeri değiştirmek için bir işlemci yazabiliriz. Aşağıdaki kodda, `elementi birinput` olayı tetiklediğinde string'in büyük harfli olmasını sağlayacağız.

<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
methods: {
emitValue(e) {
let value = e.target.value
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:modelValue', value)
}
}
}
</script>

<template>
<input type="text" :value="modelValue" @input="emitValue" />
</template>

Oyun alanında dene

Argüman ile v-model için Modifikasyonlar

Argüman ve modifikasyonları olan v-model bağlamaları için, oluşturulan prop adı arg + "Modifiers" biçiminde olacaktır. Örneğin:

<MyComponent v-model:title.capitalize="myText">

İlgili bildirimler şöyle olmalıdır:

export default {
props: ['title', 'titleModifiers'],
emits: ['update:title'],
created() {
console.log(this.titleModifiers) // { capitalize: true }
}
}

İşte argümanlarla farklı v-model kullanarak modifikasyonları örnek almak için başka bir örnek:

<UserName
v-model:first-name.capitalize="first"
v-model:last-name.uppercase="last"
/>
<script setup>
const [firstName, firstNameModifiers] = defineModel('firstName')
const [lastName, lastNameModifiers] = defineModel('lastName')

console.log(firstNameModifiers) // { capitalize: true }
console.log(lastNameModifiers) // { uppercase: true }
</script>

3.4 Öncesi Kullanım

<script setup>
const props = defineProps({
firstName: String,
lastName: String,
firstNameModifiers: { default: () => ({}) },
lastNameModifiers: { default: () => ({}) }
})
defineEmits(['update:firstName', 'update:lastName'])

console.log(props.firstNameModifiers) // { capitalize: true }
console.log(props.lastNameModifiers) // { uppercase: true }
</script>
<script>
export default {
props: {
firstName: String,
lastName: String,
firstNameModifiers: {
default: () => ({})
},
lastNameModifiers: {
default: () => ({})
}
},
emits: ['update:firstName', 'update:lastName'],
created() {
console.log(this.firstNameModifiers) // { capitalize: true }
console.log(this.lastNameModifiers) // { uppercase: true }
}
}
</script>