دایرکتیوهای سفارشی - Custom Directives
معرفی
Vue به شما امکان میدهد علاوه بر مجموعه دایرکتیوهایی که به صورت پیش فرض وجود دارد (مانند v-model
یا v-show
)، دایرکتیوهای سفارشی خود را ثبت کنید.
ما دو روش باز استفاده کد در Vue را معرفی کردیم: کامپوننت ها و کامپوزبل ها. کامپوننتها قالبهای اصلی ساخت هستند در حالیکه کامپوزبلها روی استفاده دوباره منطق با نگه داشتن وضعیت قبلی سیستم تمرکز کردهاند. از طرف دیگر، دایرکتیوهای سفارشی، اساسا برای استفاده دوباره منطقی که شامل دسترسی سطح پایین DOM به المنتهای ساده هستند تعیین شدند.
یک دایرکتیو سفارشی به عنوان یک آبجکت شامل هوکهای چرخه حیات میباشد که مشابه هوکهای کامپوننت هستند. هوکها المنتی که به دایرکتیو متصل (bound) هست را دریافت میکنند. در اینجا مثالی از یک دایرکتیو آورده شده که یک کلاس را هنگامی که Vue المنت را درون DOM وارد میکند اضافه میکند:
vue
<script setup>
// enables v-highlight in templates
const vHighlight = {
mounted: (el) => {
el.classList.add('is-highlight')
}
}
</script>
<template>
<p v-highlight>This sentence is important!</p>
</template>
This sentence is important!
در <script setup>
، هر متغیر camelCase که با پیشوند v
شروع شود میتواند به عنوان یک دایرکتیو سفارشی استفاده شود. در مثال بالا، vHighlight
میتواند در تمپلیت به صورت v-highlight
استفاده شود.
اگر از <script setup>
استفاده نمیکنید، دایرکتیوهای سفارشی میتوانند با استفاده از آپشن directives
ثبت شوند:
js
export default {
setup() {
/*...*/
},
directives: {
// enables v-highlight in template
highlight: {
/* ... */
}
}
}
همچنین ثبت سراسری دایرکتیوهای سفارشی در سطح برنامه معمول است:
js
const app = createApp({})
// make v-highlight usable in all components
app.directive('highlight', {
/* ... */
})
چه زمانی از دایرکتیوهای سفارشی استفاده کنیم
دایرکتیوهای سفارشی فقط باید زمانی استفاده شوند که عملکرد مورد نظر تنها از طریق دستکاری مستقیم DOM قابل دستیابی باشد.
یک مثال رایج از این مورد، دایرکتیو سفارشی v-focus
است که یک المان را در حالت فوکوس قرار میدهد.
vue
<script setup>
// را در تمپلیتها فعال میکند v-focus
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
این دایرکتیو از اتریبیوت autofocus
مفیدتر است زیرا نه تنها در صفحه لود شده کار میکند بلکه درون المنتهایی که به صورت پویا (dynamic) توسط Vue ساخته شدهاند نیز کار میکند!
دایرکتیوهای سفارشی فقط باید زمانی استفاده شوند که عملکرد مورد نظر فقط از طریق دستکاری مستقیم DOM حاصل شود. در صورت امکان، قالب اعلامی با استفاده از دایرکتیوهای نهادینه شده مانند v-bind
را ترجیح دهید زیرا کارامد تر و سرور-رندر دوستانه تر هستند.
هوکهای دایرکتیو
یک آبجکت دایرکتیو میتونه چندین تابع هوک چرخه حیات را فراهم کند (همگی اختیاری هستند):
js
const myDirective = {
// قبل از اتصال اتریبیوتهای المنت
// ها صدا زده میشود event listener یا اعمال شدن
created(el, binding, vnode) {
// برای جزئیات بیشتر در مورد آرگومانها به پایین مراجعه کنید
},
// شود صدا زده میشود DOM درست قبل از اینکه المنت وارد
beforeMount(el, binding, vnode) {},
// هنگامی صدا زده میشود که تمام المنتهای کامپوننت والد
// قرار گرفته DOM به همراه تمامی فرزندانش درون
mounted(el, binding, vnode) {},
// قبل از اینکه کامپوننت والد بروز رسانی شود صدا زده میشود
beforeUpdate(el, binding, vnode, prevVnode) {},
// بعد از اینکه کامپوننت والد و
// همه فرزاندش به روز رسانی شدند صدا زده میشود
updated(el, binding, vnode, prevVnode) {},
// شود صدا زده میشود Unmount قبل از اینکه کامپوننت والد
beforeUnmount(el, binding, vnode) {},
// شده Unmount هنگامی صدا زده میشود که کامپوننت والد
unmounted(el, binding, vnode) {}
}
آرگومانهای هوک
هوکهای دایرکتیو آرگومانهای زیر را قبول میکنند:
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"
به المنت دیگری ارسال شوند.