Component v-model
با استفاده از v-model
روی یک کامپوننت میتوان یک اتصال دوطرفه ایجاد کرد.
در ابتدا بیایید نگاهی دوباره داشته باشیم که چطور v-model
روی المانهای بومی Html استفاده میشود:
template
<input v-model="searchText" />
در پشت پرده، کامپایلر تمپلیت، v-model
را به معادل کاملتری برای ما تبدیل میکند. بنابراین کد بالا همان کار را انجام میدهد که کد زیر انجام میدهد:
template
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
وقتی v-model
روی یک کامپوننت استفاده شود، به جای حالت بالا به صورت زیر تبدیل میشود:
template
<CustomInput
:model-value="searchText"
@update:model-value="newValue => searchText = newValue"
/>
اما برای اینکه این کار واقعا انجام شود، کامپوننت <CustomInput>
باید دو کار انجام دهد:
- مقدار شاخصه
value
یک المان<input>
بومی را به پراپmodelValue
متصل کند - وقتی یک رویداد
input
بومی رخ میدهد، یک رویداد سفارشیupdate:modelValue
با مقدار جدید را منتشر کند
در اینجا این کار در عمل نمایش داده شده:
vue
<!-- CustomInput.vue -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
حالا v-model
باید به خوبی با این کامپوننت کار کند:
template
<CustomInput v-model="searchText" />
یک راه دیگر برای پیادهسازی v-model
درون این کامپوننت استفاده از یک پراپرتی computed
قابل نوشتن با یک getter و یک setter است. تابع get
باید مقدار پراپ modelValue
را برگرداند و تابع set
باید رویداد مربوط را منتشر کند:
vue
<!-- CustomInput.vue -->
<script setup>
import { computed } from 'vue'
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const value = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
</script>
<template>
<input v-model="value" />
</template>
v-model
آرگومانهای
به طور پیشفرض، v-model
روی یک کامپوننت از modelValue
به عنوان پراپ و update:modelValue
به عنوان رویداد استفاده میکند. میتوانیم این نامها را با افزودن یک آرگومان به v-model
تغییر دهیم:
template
<MyComponent v-model:title="bookTitle" />
در این حالت، کامپوننت فرزند باید انتظار یک پراپ title
را داشته باشد و با انتشار رویداد update:title
مقدار والد را بهروزرسانی کند:
vue
<!-- MyComponent.vue -->
<script setup>
defineProps(['title'])
defineEmits(['update:title'])
</script>
<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>
اتصال v-model
چندگانه
با استفاده از توانایی هدف قراردادن یک پراپ و رویداد خاص که در آرگومانهای v-model
یاد گرفتیم، حالا میتوانیم اتصالهای v-model
چندگانه، روی یک کامپوننت تکی ایجاد کنیم.
هر v-model
بدون نیاز به گزینههای اضافه در کامپوننت با یک پراپ مختلف همگامسازی میشود:
template
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
vue
<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>
مدیریت پیرایندههای v-model
وقتی درحال یادگیری اتصالهای input در formها بودیم، دیدیم که v-model
دارای پیرایندههای داخلی .trim
، .number
و .lazy
بود. گاهی اوقات همچنین ممکن است بخواهید که v-model
ای که روی کامپوننت سفارشیشده input خود قرار دادید هم قابلیت پشتیبانی از پیرایندههای سفارشی را داشته باشد.
بیایید یک نمونه پیراینده سفارشی بسازیم، capitalize
، که وظیفه داشته باشد حرف اول هر رشتهای که توسط اتصال v-model
فراهمشده را به حالت بزرگ آن تبدیل کند:
template
<MyComponent v-model.capitalize="myText" />
پیرایندههایی که به v-model
یک کامپوننت افزوده شده است، توسط پراپ modelModifiers
به کامپوننت ارائه میشود. در مثال زیر، ما کامپوننتی ساختیم که دارای پراپ modelModifiers
ای است که به طور پیشفرض با یک شی خالی مقداردهی شده است:
vue
<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { default: () => ({}) }
})
defineEmits(['update:modelValue'])
console.log(props.modelModifiers) // { capitalize: true }
</script>
<template>
<input
type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
توجه کنید که پراپ modelModifiers
شامل capitalize
است و مقدارش true
تنظیم شده چرا که در v-model
متصلشده، تنظیم شده است.
حالا که پراپ خود را تنظیم کردهایم، میتوانیم کلیدهای شی modelModifiers
را بررسی کنیم و یک handler برای تغییر مقدار منتشرشده بنویسیم. در قطعه کد زیر، ما حروف رشته را هر زمان که المان <input />
یک رویداد input
انتشار دهد، به حالت بزرگ تبدیل میکنیم.
vue
<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="modelValue" @input="emitValue" />
</template>
پیرایندهها برای v-model
های آرگوماندار
برای اتصالهای v-model
ای که هم پیراینده و هم آرگومان دارند، نام پراپ تولیدشده به شکل arg + "Modifiers"
خواهد بود. برای مثال:
template
<MyComponent v-model:title.capitalize="myText">
تعاریف متناظر باید به این شکل باشند:
js
const props = defineProps(['title', 'titleModifiers'])
defineEmits(['update:title'])
console.log(props.titleModifiers) // { capitalize: true }
اینجا مثال دیگری از استفاده از پیرایندهها با v-model
چندگانه با آرگومانهای مختلف را مشاهده میکنید:
template
<UserName
v-model:first-name.capitalize="first"
v-model:last-name.uppercase="last"
/>
vue
<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>