دایرکتیوهای سفارشی - Custom Directives
معرفی
Vue به شما امکان میدهد علاوه بر مجموعه دایرکتیوهایی که به صورت پیش فرض وجود دارد (مانند v-model
یا v-show
)، دایرکتیوهای سفارشی خود را ثبت کنید.
ما دو روش باز استفاده کد در Vue را معرفی کردیم: کامپوننت ها و کامپوزبل ها. کامپوننتها قالبهای اصلی ساخت هستند در حالیکه کامپوزبلها روی استفاده دوباره منطق با نگه داشتن وضعیت قبلی سیستم تمرکز کردهاند. از طرف دیگر، دایرکتیوهای سفارشی، اساسا برای استفاده دوباره منطقی که شامل دسترسی سطح پایین DOM به المنتهای ساده هستند تعیین شدند.
یک دایرکتیو سفارشی به عنوان یک آبجکت شامل هوکهای چرخه حیات میباشد که مشابه هوکهای کامپوننت هستند. هوکها المنتی که به دایرکتیو متصل (bound) هست را دریافت میکنند. در اینجا مثالی از یک دایرکتیو آورده شده که عمل فوکس(focus) را بر روی المنت input هنگاهی که Vue المنت input را درون DOM وارد میکند انجام میدهد:
vue
<script setup>
// را در تمپلیتها فعال میکند v-focus
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
با فرض اینکه شما هیچ جای صفحه کلیک نکرده باشید، input مثال بالا باید به صورت خودکار فوکس شده باشد. دایرکتیو از اتریبیوت autofocus
مفیدتر است زیرا نه تنها در صفحه لود شده کار میکند بلکه درون المنتهایی که به صورت پویا (dynamic) ساخته شدهاند نیز کار میکند.
درون <script setup>
، هر متغیری به شکل camelCase که با پیشوند v
شروع میشود میتواند به عنوان یک دایرکتیو سفارشی استفاده شود. در مثال بالا، vFocus
میتواند درون تمپلیت به صورت v-focus
استفاده شود.
اگه از <script setup>
استفاده نمیکنید، دایرکتیوهای سفارشی میتونن با استفاده از آپشن directives
معرفی شوند.
js
export default {
setup() {
/*...*/
},
directives: {
// را در تمپلیت فعال میکند v-focus
focus: {
/* ... */
}
}
}
همچنین روش رایج دیگر، ثبت کردن دایرکتیوهای سفارشی در سطح app به صورت سراسری میباشد:
js
const app = createApp({})
// را درون همه کامپوننتها قابل استفاده کن v-focus
app.directive('focus', {
/* ... */
})
نکته
دایرکتیوهای سفارشی فقط باید زمانی استفاده شوند که عملکرد مورد نظر فقط از طریق دستکاری مستقیم DOM حاصل شود. در صورت امکان، قالب اعلامی با استفاده از دایرکتیوهای نهادینه شده مانند v-bind
را ترجیح دهید زیرا کارامد تر و سرور-رندر دوستانه تر هستند.
هوکهای دایرکتیو
یک شی دایرکتیو میتونه چندین تابع هوک چرخه حیات را فراهم کند (همگی اختیاری هستند):
js
const myDirective = {
// قبل از اتصال اتریبیوتهای المنت
// ها صدا زده میشود event listener یا اعمال شدن
created(el, binding, vnode, prevVnode) {
// برای جزئیات بیشتر در مورد آرگومانها به پایین مراجعه کنید
},
// شود صدا زده میشود DOM درست قبل از اینکه المنت وارد
beforeMount(el, binding, vnode, prevVnode) {},
// هنگامی صدا زده میشود که تمام المنتهای کامپوننت والد
// قرار گرفته DOM به همراه تمامی فرزندانش درون
mounted(el, binding, vnode, prevVnode) {},
// قبل از اینکه کامپوننت والد بروز رسانی شود صدا زده میشود
beforeUpdate(el, binding, vnode, prevVnode) {},
// بعد از اینکه کامپوننت والد و
// همه فرزاندش به روز رسانی شدند صدا زده میشود
updated(el, binding, vnode, prevVnode) {},
// شود صدا زده میشود Unmount قبل از اینکه کامپوننت والد
beforeUnmount(el, binding, vnode, prevVnode) {},
// شده Unmount هنگامی صدا زده میشود که کامپوننت والد
unmounted(el, binding, vnode, prevVnode) {}
}
آرگومانهای هوک
هوکهای دایرکتیو آرگومانهای زیر را قبول میکنند:
el
: المنتی که دایرکتیو به آن متصل است. این آرگومان میتواند مستقیما برای دستکاری DOM استفاده شود.binding
: این آبجکت شامل پراپرتیهای زیر است.value
: مقداری که به دایرکتیو ارسال میشود. برای مثال درv-my-directive="1 + 1"
، مقدار ارسال شده2
خواهد بود.oldValue
: مقدار قبلی، تنها درون هوکهایbeforeUpdate
وupdated
قابل دسترس هست. خواه مقدار تغییر بکند خواه نکند این پراپرتی در دسترس هست.arg
: آرگومانی که در صورت وجود به دایرکتیو ارسال میشود. برای مثال درv-my-directive:foo
، آرگومان"foo"
میباشد.modifiers
: یک آبجکت که شامل مدیفایرها هست که در صورت وجود به دایرکتیو ارسال میشود. برای مثال درv-my-directive.foo.bar
، آبجکت شامل مدیفایرهای{ foo: true, bar: true }
میباشد.instance
: نمونهای از کامپوننتی که دایرکتیو درون آن استفاده شده.dir
: مشخصات آبجکت دایرکتیو
vnode
: نود اصلی که ارائه دهنده المنت متصل استprevNode
: نودی که ارائه دهنده المنت اصلی از رندر قبلی است. فقط درون هوکهایbeforeUpdate
وupdated
قابل دسترس هست.
به عنوان مثال، کاربرد دایرکتیو زیر را در نظر بگیرید:
template
<div v-example:foo.bar="baz">
آرگومان binding
یک شی به شکل زیر است:
js
{
arg: 'foo',
modifiers: { bar: true },
value: /* `baz` مقدار */,
oldValue: /* از بروزرسانی قبلی `baz` مقدار */
}
مشابه دایرکتیوهای نهادینه شده، آرگومانهای دایرکیتو سفارشی میتوانند پویا باشند. برای مثال:
template
<div v-example:[arg]="value"></div>
در اینجا آرگومان دایرکتیو بر اساس پراپرتی arg
درون state کامپوننت ما به صورت reactive بروزرسانی میشود.
توجه
جدا از el
، شما باید با این آرگومانها به صورت فقط خواندنی (read-only) رفتار کنید و هرگز آنها را تغییر ندهید. اگر شما نیاز دارید این اطلاعات را از طریق هوکها به اشتراک بزارید، پیشنهاد میشه که این کار را از طریق المنتهای dataset انجام دهید.
مختصر نویسی تابع
معمول است که یک دایرکتیو سفارشی برای هوکهای mounted
و updated
رفتار یکسانی داشته باشد، بدون نیاز به هوکهای دیگر. در چنین مواردی میتوانیم دایرکتیو را به صورت تابع تعریف کنیم:
template
<div v-color="color"></div>
js
app.directive('color', (el, binding) => {
// صدا زده میشود `updated` و `mounted` برای هر دو هوک
el.style.color = binding.value
})
آبجکتهای تحت اللفظی
اگر دایرکتیو شما نیازمند مقادیر مختلفی هست، شما میتوانید یک آبجکت تحت اللفظی(object literal) جاوااسکریپتی را بعنوان مقدار تعیین کنید. توجه داشته باشید که دایرکتیوها میتوانند هر عبارت معتبر جاوااسکریپتی را دریافت کنند.
template
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
js
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
کاربرد در کامپوننتها
دایرکتیوهای سفارشی همانند Fallthrough Attributes برای استفاده در کامپوننتها باید در نود ریشه (root node) به کار روند.
template
<MyComponent v-demo="test" />
template
<!-- template of MyComponent -->
<div> <!-- اینجا به کار میرود v-demo دایرکتیو -->
<span>My component content</span>
</div>
توجه داشته باشید که کامپوننتها به طور بالقوه میتوانند بیشتر از یک نود ریشه داشته باشند. یک دایرکتیو هنگامی که بر کامپوننتی با چندین نود ریشه اعمال میشود نادیده گرفته خواهد شد و اخطار داده میشود. دایرکتیوها برخلاف اتریبیوتها نمیتوانند با استفاده از v-bind="$attrs"
به المنت دیگری ارسال شوند. به طور کلی، توصیه میشود که از دایرکتیوهای سفارشی درون کامپوننتها استفاده نکنید.