انیمیشن اسکرول در انگولار – از صفر تا صد


در زمان ایجاد اپلیکیشنهای تکصفحهای در برخی موارد لازم میشود که عناصری از صفحه را در زمان اسکرول شدن انیمیت کنیم. این کار مشابه آن چیزی است که در زمان استفاده از کتابخانههای محبوب انگولار مانند aos (+) در وباپلیکیشنها از آن برخوردار میشویم. اما نکته اینجا است که هیچ کدام از کتابخانههای موجود با انگولار و روش آن برای تحریک برنامهنویسی شده انیمیشنها به خوبی تطبیق نمییابند. بنابراین در این مقاله یک راهحل برای انیمیشن اسکرول در انگولار به نام wmAnimate طراحی میکنیم. در این مقاله فرض شده است که شما با فریمورک انگولار آشنا هستید و به طورخاص با انیمیشنهای انگولار کار کردهاید.
صفحه اصلی
در این بخش یک صفحه اصلی که از کتابخانه aos استفاده میکند را مشاهده میکنید:
در این کد بخش اصلی کار با استفاده از دایرکتیو wmAnimate انجام مییابد که به کانتینر div دستور میدهد تا انیمیشنی به نام loading را با سرعت slow اجرا کند و همزمان فلگ aos تنها فلگی است که عملاً به کامپوننت اعلام میکند باید در زمان اسکرول شدن ویو تحریک شود.
کامپوننت انیمیت
دایرکتیو فوق عملاً یک کامپوننت با پیادهسازی سلکتور شبیه به دایرکتیو است که دارای چندین انیمیشن داخلی است که میتوانید از میان آنها انتخاب کنید و محتوای قالب را به حرکت درآورید تا در نهایت نتیجهای به صورت انیمیشن داشته باشید.
داشتن انیمیشنهای داخلی ممکن است محدودکننده به نظر برسد، اما در واقع روشی شبیه به روش عملکرد کتابخانههای دیگر است. از سوی دیگر این یک روش کاملاً کارآمد برای استفاده مجدد از انیمیشنها در سراسر اپلیکیشن است و برای جلوههای ورودی/خروجی که نیازمند نوعی تحریک هستند نیز به خوبی عمل میکند.
طرز کار کامپوننت
همچنان که اشاره کردیم، کامپوننت فوق چند انیمیشن داخلی پیادهسازی میکند که میتوانیم از بین آنها یکی را انتخاب کرده و دایرکتیو مربوطه را روی کانتینر اعمال کنیم.
اگر نگاهی به آرایه animations$ بیندازیم، میبینیم که کامپوننت یک انیمیشن منفرد را پیادهسازی میکند که animate@ را با یک حالت idle تحریک میکند تا عملاً کانتینر را پیش از این که تحریک رخ بدهد پنهان سازد و چند «گذار» (Transition) نیز وجود دارند که ورود و خروجهای ممکن را که میتوان از میان آنها انتخاب کرد را توصیف میکنند:
بنابراین ورودی wmAnimate به محض این که تحریک رخ بدهد، یک گذار را که قرار است کامپوننت اجرا کند انتخاب میکند. هر گذار یک مدت زمانبندی پیشفرض دارد و از این رو در صورتی که سرعتی از سوی ورودی speed تعیین نشده باشد، انیمیشن در سرعت پیشفرض خودش اجرا میشود. سرعتهای ممکن به شرح زیر هستند:
- Slower: زمانبندی 3 ثانیهای
- Slow: زمانبندی 3 ثانیهای
- Normal: زمانبندی 1 ثانیهای
- Fast: زمانبندی 500 میلیثانیهای
- Faster: زمانبندی 300 میلیثانیهای
در نهایت سه روش برای تحریک انیمیشن وجود دارد:
- به صورت پیشفرض انیمیشن ورودی به محض این که کانتینر وارد شود اجرا خواهد شد و انیمیشن خروجی نیز به محض خروج کانتینر به اجرا درمیآید.
- به صورت اختیاری میتوان انیمیشن را به صورت برنامهنویسی شده با تعیین ورودی replay روی هر مقداری که در زمان تبدیل به مقدار بولی به صوت true تبدیل میشود اجرا کرد. اساساً تعیین ورودی paused به صورت true از اجرای انیمیشن به صورت خودکار در نخستین بار جلوگیری میکند.
- در نهایت انیمیشن در زمان اسکرول با تعیین ورودی aos روی true فعال میشود. بدین ترتیب هر بار که کانتینر وارد ویو شود اجرا میشود و زمانی که از آن خارج شود در حالت idle قرار میگیرد. با این حال با تعیین ورودی once روی true از اجرای انیمیشن بیش از یک بار جلوگیری میکنیم.
زمانی که AOS فعال شود، انیمیشن در زمان ورود کانتینر به ویو تا حد 20% تحریک میشود. این مقدار را میتوان با تعیین ورودی threshold روی یک مقدار متفاوت از 0.2 تغییر داد.
تحریک انیمیشن
تحریک انیمیشن در زمان مقداردهی اولیه کامپوننت درون قلاب چرخه عمری ()ngOnInit ساخته میشود:
تابع ()animateTrigger یک observable است که به یک مقدار بولی تبدیل میشود که در زمان true بودن آن انیمیشن پخش میشود و در حالت false انیمیشن به حالت idle میرود.
زمانی که ورودی aos روی true باشد، observable بازگشتی اقدام به استفاده از ScrollDispatcher از angular/cdk@ برای ردگیری رویدادهای اسکرول شدن میکند و ناحیه همپوشان بین عنصر کانتینر و نمای اسکرول شونده را محاسبه میکند تا بر این اساس انیمیشن را تحریک کند:
جزئیات AOS
در این بخش به بررسی کد AOS به صورت گام به گام میپردازیم.
- تابع از یک observable بازگشتی از سوی متد ()ancestorScrolled از ScrollDispatcher آغاز میشود که در صورتی صادر میشود که هر یک از اجداد قابل اسکرول یک عنصر مورد اسکرول واقع شوند.
- کد زیر تضمین میکند که همه observable-ها در زمان پایان کار حذف میشوند. بهتر است در زمان استفاده از چندین observable از این متد درون کامپوننت بهره بگیریم تا همه observable-ها را بهیکباره درون قلاب چرخه عمری ()ngOnDestroy حذف کنیم. این روش بهتر از استفاده از چنین «اشتراک» (subscription) است:
takeUntil(this.dispose$)
- کد زیر تضمین میکند که نخستین مقدار صادر شده با موقعیتهای مختلف تطبیق پیدا میکند:
startWith(!this.paused && this.visibility >= this.threshold)
- خط زیر موجب میشود که مقدار ارائه شده به «نسبت نمایانی» تبدیل شود یعنی یک مقدار عددی به دست میآید که میزان ناحیهای از عنصر که در حال حاضر روی صفحه درون کانتینر اسکرول شونده دیده میشود را مشخص میکند. بدین ترتیب عدد 0 به معنی کاملاً پنهان و 1.0 به معنی کاملاً نمایان است:
map(() => this.visibility)
- خط زیر انیمیشن را بر اساس مقدار threshold تحریک میکند، در حالی که حالت idle زمانی که کانتینر دوباره کاملاً پنهان شود بازیابی میشود:
scan((result, visiblility) => …)
- خط زیر صدور مقادیر را صرفاً روی مقادیر متغیر محدود میسازد، بنابراین از صدور رویدادهای بسیار زیاد از سوی اپلیکیشن جلوگیری به عمل میآید:
distinctUntilChanged()
- خط زیر تضمین میکند که وقتی once روی true قرار گرفته باشد، صدور مقادیر در نخستین بار تحریک معتبر متوقف میشود:
takeWhile(trigger =>!trigger ||!this.once, true)
- در نهایت flatMap(trigger => …) به یک observable تبدیل میشود که در عمل درون ناحیه انگولار اجرا میشود و از این رو مکانیسم تشخیص حرکت انگولار را تحریک میکند چون ScrollDispatcher به صورت پیشفرض خارج از ناحیه انگولار فعالیت میکند تا از تأثیرات روی عملکرد جلوگیری شود.
سخن پایانی
در این مقاله یک کامپوننت به نام wmAnimate طراحی کردیم که با استفاده از آن میتوانیم انیمیشنهای در زمان اسکرول شدن صفحه در وباپلیکیشنهای انگولار اجرا کنیم. برای مشاهده کد کامل این کامپوننت به این ریپوی گیتهاب (+) مراجعه کنید.
اگر این نوشته برای شما مفید بوده است، آموزشها و مطالب زیر نیز احتمالاً برای شما مفید خواهند بود:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- مجموعه آموزشهای برنامهنویسی
- آموزش مقدماتی AngularJS برای ساخت اپلیکیشنهای تکصفحهای
- آشنایی با Angular CLI – به زبان ساده
- ۱۱ کتابخانه کامپوننت انگولار که باید بشناسید — فهرست کاربردی
==