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>