ترنزیشن - Transition
Vue دو کامپوننت داخلی ارائه میدهد که میتواند به کار با ترنزیشنها و انیمیشنها در پاسخ به تغییر وضعیت یک متغیر کمک کند:
<Transition>
برای اعمال انیمیشنها بر روی یک عنصر یا کامپوننت هنگام اضافه شدن به DOM و یا حذف از آن است. در همین صفحه به بررسی این موضوع میپردازیم.<TransitionGroup>
برای اعمال انیمیشنها بر روی یک عنصر یا کامپوننت زمانی که آیتمی به لیستv-for
اضافه شده و یا از آن حذف شده و یا اینکه در آن جا به جا شده است. این موضوع در بخش بعدی بررسی شده است.
جدا از این دو کامپوننت، میتوانیم انیمیشنها را در Vue با استفاده از موارد دیگر نیز اعمال کنیم. تکنیکهایی مانند کلاسهای CSS یا انیمیشنهای state محور که به استایل متصل میشوند. این تکنیکهای اضافی در بخش تکنیکهای انیمیشن بررسی شده است.
کامپوننت <Transition>
<Transition>
یک کامپوننت داخلی است: این به آن معنی است که شما میتوانید از آن در تمپلیت هر کامپوننتی بدون اینکه آن را ایمپورت کنید استفاده کنید. از آن میتوانید برای انیمیشنهای ورود و خروج هر عنصر یا کامپوننتی که در slot پیش فرض آن قرار گرفته است استفاده کنید. این انیمیشن میتواند توسط یکی از راه های زیر فعال شود:
- رندر شرطی با استفاده از
v-if
- نمایش شرطی با استفاده از
v-show
- جابجایی کامپوننت به شکل پویا با استفاده از عنصر ویژه
<component>
- تغییر اتریبیوت ویژه
key
این یک نمونه از ابتداییترین کاربرد آن است:
template
<button @click="show = !show">Toggle</button>
<Transition>
<p v-if="show">hello</p>
</Transition>
css
/* در ادامه توضیح خواهیم داد که این کلاسها چه میکنند! */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
hello
نکته
<Transition>
فقط از یک عنصر یا کامپوننت به عنوان محتوای slot خود پشتیبانی میکند. اگر محتوا یک کامپوننت باشد، کامپوننت نیز باید تنها یک عنصر ریشه داشته باشد.
هنگامی که یک عنصر در کامپوننت <Transition>
درج یا حذف میشود، این اتفاق میافتد:
Vue به طور خودکار تشخیص می دهد که آیا عنصر هدف دارای ترنزیشن CSS یا انیمیشن اعمال شده است. در این صورت، تعدادی از کلاسهای ترنزیشن CSS در زمانهای مناسب اضافه/حذف خواهند شد.
اگر شنوندههایی برای هوکهای جاوااسکریپت وجود داشته باشد، این هوکها در زمانهای مناسب فراخوانی میشوند.
اگر هیچ ترنزیشن / انیمیشن CSS شناسایی نشود و هیچ هوک جاوااسکریپتی ارائه نشود، عملیات DOM برای درج و یا حذف در فریم بعدی انیمیشن مرورگر اجرا میشود.
ترنزیشن های مبتنی بر CSS
کلاسهای ترنزیشن
شش کلاس برای ترنزیشنهای ورود یا خروج اعمال میشود.
v-enter-from
: حالت شروع برای ورود. قبل از اضافه کردن عنصر، اضافه میشود، یک فریم پس از اضافه کردن عنصر، حذف میشود.v-enter-active
: حالت فعال برای ورود. در طول تمام فاز ورود اعمال میشود. قبل از اضافه کردن عنصر اضافه میشود، وقتی که ترنزیشن/انیمیشن پایان مییابد حذف میشود. از این کلاس میتوان برای تعریف مدت زمان، تاخیر و منحنی انعطافپذیری برای ترنزیشن ورودی استفاده کرد.v-enter-to
: حالت پایانی برای ورود. یک فریم پس از اضافه شدن عنصر، اضافه میشود (همزمان با حذفv-enter-from
)، وقتی که ترنزیشن/انیمیشن پایان مییابد، حذف میشود.v-leave-from
: حالت شروع برای خروج. فوراً پس از ایجاد ترنزیشن خروجی اضافه میشود، یک فریم پس از آن حذف میشود.v-leave-active
: حالت فعال برای خروج. در طول تمام فاز خروج اعمال میشود. فوراً پس از ایجاد ترنزیشن خروجی اضافه میشود، وقتی که ترنزیشن/انیمیشن پایان مییابد حذف میشود. از این کلاس میتوان برای تعریف مدت زمان، تاخیر و منحنی انعطافپذیری برای ترنزیشن خروجی استفاده کرد.v-leave-to
: حالت پایانی برای خروج. یک فریم پس از ایجاد ترنزیشن خروجی اضافه میشود (همزمان با حذفv-leave-from
)، وقتی که ترنزیشن/انیمیشن پایان مییابد حذف میشود.
v-enter-active
و v-leave-active
به ما این امکان را میدهند که منحنیهای انعطافپذیر متفاوتی را برای ترنزیشن های ورودی/خروجی مشخص کنیم، که یک نمونه از آن را در بخشهای آینده خواهیم دید.
ترنزیشنهای دارای نام
یک ترنزیشن میتواند از طریق پراپ name
نامگذاری شود:
template
<Transition name="fade">
...
</Transition>
برای یک ترنزیشن نامدار، کلاسهای آن ترنزیشن با نام آن پیشوند داده میشود به جای v
. به عنوان مثال، کلاس اعمال شده برای ترنزیشن فوق به جای fade-enter-active
، v-enter-active
خواهد بود. کد CSS برای ترنزیشن fade به این صورت میباشد:
css
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
ترنزیشنهای CSS
<Transition>
بیشترین استفاده را همراه با ترنزیشنهای بومی CSS دارد، همانطور که در مثال ابتدایی دیده شد. ویژگی transition
در CSS یک مختصرنویسی است که به ما این امکان را میدهد که جزئیات متعددی از یک ترنزیشن را مشخص کنیم، از جمله خصوصیاتی که باید انیمه شوند، مدت زمان گذر و منحنیهای انعطافپذیری.
در ادامه یک مثال پیشرفتهتر آورده شده است که برای ترنزیشنهای ورودی و خروجی، پراپرتیهای متعددی را با مدت زمان و منحنیهای انعطافپذیر مختلف ترنزیشن نشان میدهد:
template
<Transition name="slide-fade">
<p v-if="show">hello</p>
</Transition>
css
/*
انیمیشنهای ورودی و خروجی میتوانند
از مدتها و توابع زمانی مختلف استفاده کنند
*/
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
hello
انیمیشنهای CSS
انیمیشنهای بومی CSS به مشابه با ترنزیشنهای CSS استفاده میشوند، با این تفاوت که *-enter-from
فوراً پس از اضافه شدن عنصر حذف نمیشود، بلکه در رویداد animationend
حذف میشود.
برای اکثر انیمیشنهای CSS، میتوانیم آنها را به سادگی در داخل کلاسهای *-enter-active
و *-leave-active
مشخص کنیم. در اینجا یک مثال برای آن داریم:
template
<Transition name="bounce">
<p v-if="show" style="text-align: center;">
Hello here is some bouncy text!
</p>
</Transition>
css
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
سلام، اینجا متنی پَرشی داریم!
کلاسهای ترنزیشن سفارشی
همچنین میتوانید کلاسهای ترنزیشن سفارشی را با ارسال پراپهای زیر به <Transition>
مشخص کنید:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
این کلاسها نامهای معمولی کلاس را بازنویسی میکنند. این به خصوص مفید است زمانی که میخواهید سیستم ترنزیشن Vue را با یک کتابخانه انیمیشن CSS موجود مانند Animate.css ترکیب کنید:
template
<!-- در صفحه وجود دارد Animate.css فرض کنید که -->
<Transition
name="custom-classes"
enter-active-class="animate__animated animate__tada"
leave-active-class="animate__animated animate__bounceOutRight"
>
<p v-if="show">hello</p>
</Transition>
استفاده از ترنزیشنها و انیمیشنها به صورت همزمان
Vue برای اطلاع از اینکه یک ترنزیشن به پایان رسیده است، نیاز به اتصال گوش کنندههای رویداد دارد. این ممکن است یا transitionend
یا animationend
باشد، بسته به نوع قوانین CSS اعمال شده. اگر فقط از یکی از آنها استفاده میکنید، Vue میتواند به صورت خودکار نوع صحیح را تشخیص دهد.
هرچند در برخی موارد ممکن است بخواهید هر دوی آنها را بر روی یک عنصر داشته باشید؛ به عنوان مثال، یک انیمیشن CSS که توسط Vue فعال میشود، همراه با یک افکت گذری CSS هنگام هاور موس. در این موارد، شما باید به صراحت نوعی که میخواهید Vue اهمیت بدهد را با ارسال پراپ type
با مقدار animation
یا transition
اعلام کنید:
template
<Transition type="animation">...</Transition>
ترنزیشنهای تو در تو و مدت زمانهای دقیق ترنزیشن
هرچند که کلاسهای ترنزیشن فقط بر روی عنصر فرزند مستقیم در <Transition>
اعمال میشوند، ما میتوانیم عنصرهای تو در تو را با استفاده از انتخابگرهای CSS تو در تویی انتقال دهیم:
template
<Transition name="nested">
<div v-if="show" class="outer">
<div class="inner">
Hello
</div>
</div>
</Transition>
css
/* قوانینی که به عنصرهای تو در تو اشاره میکنند */
.nested-enter-active .inner,
.nested-leave-active .inner {
transition: all 0.3s ease-in-out;
}
.nested-enter-from .inner,
.nested-leave-to .inner {
transform: translateX(30px);
opacity: 0;
}
/* حذف شده است CSS سایر قسمتهای ضروری از */
میتوانیم حتی یک تاخیر ترنزیشن را به عنصر تو در تو در حال ورود اضافه کنیم که یک دنباله انیمیشن ورود گامبهگام ایجاد میکند:
css
/* تاخیر ورود عنصر تو در تو برای ایجاد اثر گامبهگام */
.nested-enter-active .inner {
transition-delay: 0.25s;
}
با این حال، این یک مشکل کوچک ایجاد میکند. به صورت پیشفرض، کامپوننت <Transition>
سعی میکند به طور خودکار فهمیدن اینکه ترنزیشن به پایان رسیده یا خیر را با گوش دادن به اولین رویداد transitionend
یا animationend
بر روی عنصر ترنزیشن اصلی انجام دهد. با یک ترنزیشن تو در تو، رفتار مطلوب انتظار کشیدن تا زمانی که ترنزیشنهای همه عنصرهای داخلی به پایان رسیده باشند میباشد.
در چنین مواردی، میتوانید مدت زمان ترنزیشن را به صورت دقیق (به میلیثانیه) با استفاده از پراپ duration
بر روی کامپوننت <transition>
مشخص کنید. مدت زمان کل باید با جمع تاخیر و مدت زمان ترنزیشن عنصر داخلی همخوانی داشته باشد:
template
<Transition :duration="550">...</Transition>
Hello
آن را در Playground امتحان کنید
اگر لازم باشد، میتوانید مقادیر جداگانه برای مدت زمان ورود و خروج با استفاده از یک آبجکت مشخص کنید:
template
<Transition :duration="{ enter: 500, leave: 800 }">...</Transition>
در نظر گرفتن عملکرد
ممکن است توجه کنید که انیمیشنهای نشان داده شده بیشتر از پراپهایی مانند transform
و opacity
استفاده میکنند. این پراپها به دلیل کارآیی زیر به راحتی قابل انیمیشنسازی هستند:
آنها در طول انیمیشن بر لایهبندی داکیومنت تأثیر نمیگذارند، بنابراین محاسبات گران لایهبندی CSS را در هر فریم انیمیشن فراخوانی نمیکنند.
بیشتر مرورگرهای مدرن میتوانند هنگام انیمیشن
transform
از شتابدهنده سختافزاری GPU بهره ببرند.
در مقابل، پراپهایی مانند height
یا margin
طرحبندی CSS را فراخوانی میکنند، بنابراین انیمیشن دادن به آنها بسیار هزینه بر است و باید با احتیاط استفاده شوند.
هوکهای جاوااسکریپت
شما میتوانید با گوش دادن به رویدادها بر روی کامپوننت <Transition>
به فرآیند ترنزیشن با جاوااسکریپت متصل شوید:
html
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<!-- ... -->
</Transition>
js
// درج شود فراخوانی میشود DOM قبل از اینکه عنصر در
// عنصر تنظیم شود 'enter-from' از این استفاده کنید تا وضعیت
function onBeforeEnter(el) {}
// یک فریم پس از اضافه شدن عنصر فراخوانی میشود
// از این استفاده کنید تا انیمیشن ورودی شروع شود
function onEnter(el, done) {
// را فراخوانی کنید done برای نشان دادن پایان ترنزیشن تابع
// استفاده شود، اختیاری است CSS اگر با
done()
}
// زمانی فراخوانی میشود که ترنزیشن ورودی به پایان رسیده باشد
function onAfterEnter(el) {}
// زمانی فراخوانی میشود که ترنزیشن ورودی قبل از کامل شدن لغو شود
function onEnterCancelled(el) {}
// قبل از فراخوانی ترنزیشن خروجی فراخوانی میشود
// بیشتر مواقع، بهتر است فقط از هوک خروجی استفاده کنید
function onBeforeLeave(el) {}
// زمانی فراخوانی میشود که ترنزیشن خروجی شروع میشود
// از این استفاده کنید تا انیمیشن خروجی شروع شود
function onLeave(el, done) {
// را فراخوانی کنید done برای نشان دادن پایان ترنزیشن تابع
// استفاده شود، اختیاری است CSS اگر با
done()
}
// زمانی فراخوانی میشود
// حذف شده باشد DOM که ترنزیشن خروجی به پایان رسیده و عنصر از
function onAfterLeave(el) {}
// در دسترس است v-show تنها در ترنزیشنهای
function onLeaveCancelled(el) {}
این هوکها میتوانند در ترکیب با ترنزیشنها / انیمیشنهای CSS یا به تنهایی استفاده شوند.
به طور معمول در هنگام استفاده از ترنزیشنها، تنها با استفاده از JavaScript، ایدهی خوبی است که پراپ :css="false"
را اضافه کنید. این پراپ به طور صریح به Vue میگوید که از شناسایی خودکار ترنزیشن CSS صرف نظر کند. به جز کمی بهبود کارایی، همچنین از اینکه قوانین CSS به طور اتفاقی با ترنزیشن تداخل داشته باشند جلوگیری میکند:
template
<Transition
...
:css="false"
>
...
</Transition>
با استفاده از :css="false"
، ما همچنین به صورت کامل مسئول کنترل زمان پایان ترنزیشن هستیم. در این حالت، کالبکهای done
برای هوکهای @enter
و @leave
لازم است. در غیر این صورت، هوکها به صورت همزمان فراخوانی میشوند و ترنزیشن به سرعت به پایان میرسد.
در اینجا یک نمونه دمو با استفاده از کتابخانه GSAP برای انجام انیمیشنها وجود دارد. البته، میتوانید از هر کتابخانه دیگری که مایلید، مانند Anime.js یا Motion One، استفاده کنید:
ترنزیشنهای قابل استفاده مجدد
ترنزیشنها از طریق سیستم کامپوننت Vue قابل استفاده مجدد هستند. برای ایجاد یک ترنزیشن قابل استفاده مجدد، میتوانیم یک کامپوننت ایجاد کنیم که <Transition>
را دربربگیرد و محتوای اسلات را به آن منتقل کند:
vue
<!-- MyTransition.vue -->
<script>
// JavaScript منطق هوکهای
</script>
<template>
<!-- از پیش ساخته شده Transition دربرگرفتن کامپوننت -->
<Transition
name="my-transition"
@enter="onEnter"
@leave="onLeave">
<slot></slot> <!-- جای گذاری محتوای اسلات -->
</Transition>
</template>
<style>
/*
ضروری CSS استایلهای
در اینجا خودداری کنید `<style scoped>` توجه: از استفاده از
زیرا به محتوای اسلات اعمال نمیشود
*/
</style>
حالا MyTransition
میتواند import شده و مانند یک نسخهی از پیش ساخته شده استفاده شود:
template
<MyTransition>
<div v-if="show">Hello</div>
</MyTransition>
ترنزیشن در هنگام ظاهر شدن
اگر میخواهید همچنین یک ترنزیشن را در زمان اولیه نمایش یک عنصر اعمال کنید، میتوانید پراپ appear
را اضافه کنید:
template
<Transition appear>
...
</Transition>
ترنزیشن بین عناصر
علاوه بر تغییر وضعیت یک عنصر با v-if
/ v-show
، ما همچنین میتوانیم بین دو عنصر ترنزیشن دهیم با استفاده از v-if
/ v-else
/ v-else-if
، تا زمانی که اطمینان حاصل شود که تنها یک عنصر در هر لحظه نمایش داده میشود:
template
<Transition>
<button v-if="docState === 'saved'">Edit</button>
<button v-else-if="docState === 'edited'">Save</button>
<button v-else-if="docState === 'editing'">Cancel</button>
</Transition>
Click to cycle through states:
آن را در Playground امتحان کنید
حالتهای ترنزیشن
در مثال قبلی، عناصر ورودی و خروجی به یک زمان انیمیشن داده شدند، و ما مجبور بودیم آنها را به position: absolute
تنظیم کنیم تا از مشکل طراحی جلوگیری کنیم زمانی که هر دو عنصر در DOM حاضر باشند.
با این حال، در برخی موارد این امکان وجود ندارد یا به عنوان رفتار مطلوب شناخته نمیشود. ممکن است بخواهیم عنصر ورودی فقط پس از پایان انیمیشن خروجی درج شود. مدیریت این انیمیشنها به صورت دستی بسیار پیچیده خواهد بود. خوشبختانه، میتوانیم این رفتار را با ارسال یک پراپ mode
به <Transition>
فعال کنیم:
template
<Transition mode="out-in">
...
</Transition>
در ادامه نمونه قبلی با mode="out-in"
آورده شده است:
Click to cycle through states:
<Transition>
همچنین از mode="in-out"
پشتیبانی میکند، اگرچه استفاده از آن کمتر متداول است.
ترنزیشن بین کامپوننتها
<Transition>
همچنین میتواند برای کامپوننتهای پویا استفاده شود:
template
<Transition name="fade" mode="out-in">
<component :is="activeComponent"></component>
</Transition>
Component A
ترنزیشنهای پویا
پراپهای <Transition>
مانند name
نیز میتوانند پویا باشند! این به ما این امکان را میدهد که بر اساس تغییر وضعیت، به طور پویا ترنزیشنهای مختلف اعمال کنیم:
template
<Transition :name="transitionName">
<!-- ... -->
</Transition>
این مفید است زمانی که ترنزیشنها / انیمیشنهای CSS را با استفاده از کنوانسیون کلاس ترنزیشن Vue تعریف کردهاید و میخواهید بین آنها تغییر کنید.
همچنین میتوانید بر اساس state فعلی کامپوننت خود، رفتار مختلف را در هوکهای ترنزیشن JavaScript اعمال کنید. در نهایت، راه حقیقی ایجاد ترنزیشنهای پویا از طریق کامپوننتهای انتقال قابل استفاده مجدد است که پراپها را برای تغییر خصوصیات ترنزیشن(ها) مورد استفاده، دریافت میکنند.ممکن است خنده دار به نظر برسد، اما تنها محدودیت، خلاقیت شماست.
ترنزیشن با اتریبیوت key
گاهی اوقات شما نیاز دارید که یک عنصر DOM را دوباره رندر کنید تا یک ترنزیشن رخ دهد.
برای مثال این کامپوننت شمارنده را در نظر بگیرید:
vue
<script setup>
import { ref } from 'vue';
const count = ref(0);
setInterval(() => count.value++, 1000);
</script>
<template>
<Transition>
<span :key="count">{{ count }}</span>
</Transition>
</template>
در صورتی که اتریبیوت key
را از کد حذف کنیم، فقط متن المنت به روز میشود و هیچ ترنزیشنی رخ نمیدهد. با این حال، با وجود اتریبیوت key
، فریمورک Vue میداند که هر زمان که count
تغییر کرد، یک عنصر span
جدید ایجاد کند و بنابراین کامپوننت Transition
دارای 2 عنصر مختلف برای ترنزیشن بین آنها است.
مرتبط