تکمیل پروژه و اضافه‌کردن انیمیشن

Complete the Project and Add Animation

14 آبان 1399
Vue.JS 2: تکمیل پروژه و اضافه کردن انیمیشن - قسمت 69

در جلسه قبل کامپوننت Question.vue را کدنویسی کردیم و حالا نوبت به کامپوننت Answer.vue می رسد. من کدهای ساده آن را برایتان قرار می دهم:

<template>
  <div class="alert alert-success text-center">
    <h1>That's Correct!</h1>
    <hr />
    <button class="btn btn-primary" @click="onNextQuestion">Next Question</button>
  </div>
</template>
<style>
</style>
<script>
export default {
  methods: {
    onNextQuestion() {
      this.$emit("confirmed");
    }
  }
};
</script>

عنوان این صفحه that's correct (به معنی «صحیح است») می باشد چرا که این کامپوننت بارگذاری نخواهد شد مگر آنکه کاربر پاسخ صحیح را بدهد. در صورتی که پاسخ غلط را انتخاب کند فقط یک پنجره alert نمایش خواهیم داد. همانطور که در کد بالا مشخص است من دکمه ای به نام Next Question (سوال بعدی) دارم که با کلیک روی آن متدی به نام onNextQuestion اجرا می شود. این متد تنها confirmed را emit می کند. اگر یادتان باشد کامپوننت Question.vue نیز answered را emit می کرد، بنابراین می توانیم به App.vue برگردیم و به این دو رویداد گوش کنیم. من ابتدا به App.vue می روم و رویداد answered را دریافت می کنم:

<div class="row">
  <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
    <component :is="mode" @answered="answered($event)"></component>
  </div>
</div>

همانطور که مشخص است من event$ را نیز گرفته ام و آن را به متدی به نام answered پاس داده ام که هنوز تعریف نشده است. اگر یادتان باشد event$ متغیر مخصوصی بود که اطلاعات پاس داده شده به همراه رویداد را با خود داشت و رویداد answered از کامپوننت Question.vue ارسال شده است:

onAnswer(isCorrect) {
  this.$emit("answered", isCorrect);
}

بنابراین event$ همان isCorrect است که از Question.vue ارسال شده و در App.vue گرفته می شود. در مرحله بعد باید confirmed را دریافت کنیم بنابراین:

<div class="row">
  <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
    <component :is="mode" @answered="answered($event)" @confirmed="mode = 'app-question'"></component>
  </div>
</div>

یعنی زمانی که confirmed دریافت شد mode برنامه را به app-question تغییر بده. با این کار خصوصیت is تغییر می کند و کامپوننت Question.vue دوباره بارگذاری می شود و اگر یادتان باشد در جلسه قبل از lifecycle hook ای به نام created استفاده کردیم تا هنگام بارگذاری Question.vue سریعا یک سوال جدید تولید شود. در مرحله بعد در همان فایل App.vue به قسمت script رفته و متد answered را تعریف می کنیم:

<script>
import Question from "./components/Question.vue";
import Answer from "./components/Answer.vue";

export default {
  data() {
    return {
      mode: "app-question"
    };
  },
  methods: {
    answered(isCorrect) {
      if (isCorrect) {
        this.mode = "app-answer";
      } else {
        this.mode = "app-question";
        alert("Wrong, try again!");
      }
    }
  },

isCorrect از کامپوننت Question.vue پاس داده می شود و یک مقدار Boolean است که مشخص می کند پاسخ کاربر صحیح (true) یا غلط (false) بوده است. شرط بالا نیز دقیقا همین مسئله را چک می کند تا اگر isCorrect صحیح بود، کامپوننت answer.vue بارگذاری شود و اگر غلط بود mode را روی کامپوننت question.vue قرار می دهیم (البته باید در همین حالت باشد اما محض اطمینان این کد را نوشته ایم). در نهایت یک alert هم نشان می دهیم که پاسخ انتخاب شده اشتباه است. حالا برنامه ما کامل شده است اما انیمیشن ندارد و باید آن را نیز اضافه کنیم.

اضافه کردن انیمیشن به برنامه

 برای شروع این کار می دانیم که باید از transition استفاده کنیم، بنابراین:

<div class="row">
  <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
    <transition name="flip" mode="out-in">
      <component :is="mode" @answered="answered($event)" @confirmed="mode = 'app-question'"></component>
    </transition>
  </div>
</div>

یعنی نام انیمیشن من flip خواهد بود و mode آن نیز روی out-in است تا ابتدا عنصر قبلی از بین برود و سپس عنصر جدید به آن اضافه شود. با این حساب باید به قسمت Style در همین فایل (App.vue) برویم و بگوییم:

<style>
.flip-enter {
  /*transform: rotateY(0deg);*/
}

.flip-enter-active {
  animation: flip-in 0.5s ease-out forwards;
}

.flip-leave {
  /*transform: rotateY(0deg);*/
}

.flip-leave-active {
  animation: flip-out 0.5s ease-out forwards;
}

@keyframes flip-out {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(90deg);
  }
}

@keyframes flip-in {
  from {
    transform: rotateY(90deg);
  }
  to {
    transform: rotateY(0deg);
  }
}
</style>

flip یعنی «برگرداندن». ما در ابتدا دو keyframe را تعریف کرده ایم که باید به آن ها توجه کنیم. به flip-out نگاه کنید: در from یا لحظه شروع انیمیشن، rotate (چرخش در محور عمودی) برابر 0 است چرا که در شروع نباید شکل غیر عادی باشد. در to که آخرین لحظه انیمیشن است هم آن را روی 90 درجه گذاشته ایم تا 90 درجه بچرخد که نصف انیمیشن ما است (انیمیشن ما می خواهد یک دور کامل بزند بنابراین 180 درجه خواهیم داشت). زمانی که به 90 درجه برسیم کامپوننت فعلی ما حذف شده و کامپوننت جدید جایگزین می شود بنابراین 90 درجه بعدی را در آن نوشته ایم. اگر تمام چرخش 180 درجه را در keyframe اول انجام بدهیم، عنصر از دیده ما محو می شود چرا که پشت هر عنصری خالی است و 180 درجه چرخش در محور عمودی یعنی پشت کردن عنصر به ما. من نمی خواهم اینطور شود، بلکه می خواهم به محض حذف شدن کامپوننت اول، کامپوننت بعدی نمایش داده شود. برای flip-in نیز از 90 درجه شروع کرده ایم و به صفر رسیده ایم.

همچنین کلاس flip-enter نیازی به rotateY روی صفر ندارد چرا که در شروع انیمیشن هستیم و قطعا کامپوننت ما در همین حالت است اما آن را به صورت کامنت برایتان قرار داده ام تا بدانید. همین کار را برای flip-leave نیز انجام داده ایم. سپس انیمیشن های تعریف شده در keyframe ها را مثل همیشه به flip-enter-active و flip-leave-active داده ام که چیز خاصی ندارند.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.