جدید در Vue.js 3.3: اتصال دو طرفه با ماکرو defineModel

با نسخه 3.3 آینده VueJS، جامعه بار دیگر ناامید نمیشود و بسیاری از ویژگیهای مفید را برای توسعهدهندگان منتشر میکند تا بهرهوری بیشتری داشته باشند و ویژگیها را سریعتر ارسال کنند.
یکی از ویژگی هایی که به تازگی مورد استقبال قرار گرفته است defineModel است که به ما امکان می دهد اتصال دو طرفه بسیار روان تری را پیاده سازی کنیم. بیایید استفاده از آن را در پست وبلاگ زیر نشان دهیم.
2-Way Binding چیست؟
اتصال دو طرفه یک ویژگی در VueJS است که به تغییرات داده اجازه می دهد تا نمای را به طور خودکار به روز کند و بالعکس. این بدان معناست که وقتی کاربر نمای را به روز می کند، داده های زیربنایی نیز به روز می شوند و زمانی که داده ها به صورت برنامه ای به روز می شوند، نما به طور خودکار به روز می شود تا داده های جدید را منعکس کند. با استفاده از v-model
دستورالعمل، که یک عنصر ورودی فرم را به یک قطعه داده متصل می کند.
<template>
<input v-model="message" />
</template>
<script setup>
import { ref } from 'vue'
const message = ref('Hello from Bitovi!')
</script>
اتصال دو طرفه مفید است زیرا نیاز به مدیریت رویداد دستی برای همگام نگه داشتن نما و داده ها را از بین می برد، که می تواند خسته کننده و مستعد خطا باشد. استفاده از v-model معادل است
<template>
<input
:value="message"
@input="message = $event.target.value"
/>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('Hello from Bitovi!')
</script>
صحافی دو طرفه سفارشی
یک مثال ممکن است داشتن یک مؤلفه جستجوی سفارشی باشد که به کاربر اجازه می دهد مقداری را در جستجو تایپ کند، که چندین گزینه را تا زمانی که یکی را انتخاب کند نمایش می دهد. این رفتار در کد زیر نشان داده شده است:
// MySearch.vue
<template>
<div>
<!-- search text input -->
<input v-model="searchRef" type="text" placeholder="Search"/>
<!-- display selected value -->
<div v-if="props.modelValue">
Selected: {{ props.modelValue.title }}
</div>
<!-- results -->
<div v-if="searchRef.length > 3">
<button
v-for="data in store.getLoadedElements"
:key="data.id"
@click="onClick(data)"
>
{{ data.title }}
</button>
</div>
</div>
</template>
<script setup lang="ts">
// imports
const store = useStore();
const props = defineProps({
modelValue: {
type: Object as PropType<Element | null>,
required: true,
default: null
}
});
const emit = defineEmits<{
(e: "update:modelValue", value: Element): void;
}>();
// reference to search input
const searchRef = ref<string>("");
// fetch data from API
watchEffect(() => {
store.fetchElements(searchRef.value);
});
const onClick = (data: Element) => {
emit("update:modelValue", data);
};
</script>
در مثال بالا، برای اینکه صحافی سفارشی دو طرفه کار کند، از استفاده می کنید defineProps
برای ایجاد یک modelValue
ویژگی ورودی برای کامپوننت و شما از آن استفاده می کنید defineEmits
با update:modelValue
برای اطلاع والدین در مورد تغییر.
استفاده از مؤلفه فرزند فوق با نحو زیر در مؤلفه دیگر به دست می آید.
<MySearch v-model="someRef" />
<!-- same as -->
<MySearch
:modelValue="someRef"
@update:modelValue="someRef = $event"
/>
توجه داشته باشید: یک نکته مفید این است که می توانید چندین ویژگی را برای آن تعریف کنید
MySearch
جزء به defineProps وdefineEmits
. نامmodelValue
نام مقدار پیشفرض است، با این حال با ایجاد چندین ویژگی، میتوانید به آنها در مؤلفه والد دسترسی داشته باشید<MySearch v-model:first="first" v-model:second="second"/>
.
با استفاده از defineModel
با نسخه آینده VueJS، 3.3 یک نسخه جدید است ماکرو defineModel، دیگر نیازی به نوشتن تمام مراحل ذکر شده در بالا برای اجرای اتصال دو طرفه سفارشی ندارید.
این ویژگی جدید از نسخه 3.3.0-alpha.9 در دسترس است، با این حال، هنوز یک ویژگی آزمایشی در نظر گرفته می شود. اگر مایل به استفاده از آن هستید یا در ارتقاء به نسخه 3.3m مشکل دارید، همچنان می توانید از جایگزین آن، defineModels، از کتابخانه Vue Macros استفاده کنید، که این ویژگی از آن الهام گرفته شده است. به طور کلی آنها به همان روش کار می کنند.
پس از تکمیل دستورالعمل های نصب، می توانید از defineModels با سینتکس زیر استفاده کنید:
// MySearch.vue
<template>
<div>
<!-- search text input -->
<input v-model="searchRef" type="text" placeholder="Search"/>
<!-- display selected value -->
<div v-if="modelValue">Selected: {{ modelValue.title }}</div>
<!-- results -->
<div v-if="searchRef.length > 3">
<button
v-for="data in store.getLoadedElements"
:key="data.title"
@click="modelValue = data"
>
{{ data.title }}
</button>
</div>
</div>
</template>
<script setup lang="ts">
// imports
const store = useStore();
const { modelValue } = defineModels<{ modelValue: Element }>();
// reference to search input
const searchRef = ref<string>("");
// fetch data from API
watchEffect(() => {
store.fetchElements(searchRef.value);
});
</script>
ماکرو defineModels
جایگزین موارد استفاده شده قبلی می شود defineProps
و defineEmits
به یک عملکرد
هر بار، کاربر مقداری را به این مؤلفه ارسال می کند <MySearch :modelValue="someRef" />
را MySearch
کامپوننت به روز می شود و همچنین در خط 16 وقتی کاربر عنصری را انتخاب می کند، توسط modelValue = data
، شنونده در مؤلفه والد فعال می شود.
خلاصه
دیدن این که تیم VueJS کمکهای ارزشمند توسعهدهندگان به اکوسیستم VueJS را میشناسد و به مرور زمان پیادهسازی آنها را ارسال میکند، بسیار خوب است. با نسخه 3.3 آینده، VueJS ابزارهای مفید دیگری را برای ما به ارمغان می آورد که توسعه ما را سرعت می بخشد.