استفاده از یک شیء سراسری Vue

Using a Global Vue Object

37-Vue-Complete-Course-2020

در جلسه قبل در رابطه با دو روش انتقال اطلاعات بین کامپوننت های خواهر و برادر صحبت کردیم. اولین روش استفاده از custom event ها و دومین روش استفاده از Callback ها بود. هر دوی این روش ها بر محور ثابتی کار می کردند: انتقال اطلاعات به کامپوننت پدر و سپس انتقال آن به کامپوننت برادر. مشکل این روش اینجاست که در برنامه های واقعی تعداد کامپوننت های تو در تو بسیار زیاد خواهد بود و پاس دادن اطلاعات به این روش تقریبا غیرممکن خواهد شد.

در این جلسه نوبت به کار با روش سوم می رسد که روش استاندارد تری می باشد. در این روش از یک کلاس یا شیء سراسری خواهیم داشت که از تمام قسمت های برنامه قابل دسترس است بنابراین برای پاس دادن اطلاعات از آن استفاده می کنیم. اگر با فریم ورک Angular آشنا باشید با این مفهوم آشنا هستید (در Angular به آن services می گویند).

برای شروع کار وارد فایل main.js شده و یک شیء Vue جدید ایجاد کنید. البته آن را Export خواهیم کرد بنابراین باید درون یک ثابت نیز ذخیره شود:

import Vue from 'vue'
import App from './App.vue'

export const eventBus = new Vue();

new Vue({
  el: '#app',
  render: h => h(App)
});

من هیچ متد یا خصوصیتی را برای این شیء Vue ارسال نمی کنم چرا که تمام خصوصیات و متدهای من از قبل در فایل هایم تعریف شده است. توجه داشته باشید که حتما باید eventBus را قبل از شیء اصلی خود تعریف کنید چرا که ما می خواهیم درون شیء اصلی Vue از eventBus استفاده کنیم بنابراین حتما از قبل آماده شده باشد.

حالا وارد فایل userEdit.vue شده و این شیء را import کنید:

<script>
import { eventBus } from "../main";

export default {
  props: ["userAge"],
  methods: {
    editAge() {
      this.userAge = 30;
      // this.$emit("ageWasEdited", this.userAge);
    }
  }
};
</script>

همانطور که می بینید من متد emit را کامنت و غیر فعال کرده ام چرا که دیگر نیازی به آن نداریم. راه حل جدید این است که emit را روی eventBus صدا بزنیم (eventBus یک شیء Vue ساده است و چیز خاصی نیست بنابراین متد emit را در خود دارد):

<script>
import { eventBus } from "../main";

export default {
  props: ["userAge"],
  methods: {
    editAge() {
      this.userAge = 30;
      // this.$emit("ageWasEdited", this.userAge);
      eventBus.$emit("ageWasEdited", this.userAge);
    }
  }
};
</script>

همانطور که می بینید اطلاعات همان اطلاعات قبلی است و تفاوت فقط در این است که روش قبلی از this استفاده می کرد یا به زبان ساده تر emit را روی همین شیء Vue صدا می زد اما با این روش، آن را روی یک شیء Vue دیگر صدا می زنیم (eventBus). حالا می توانیم به فایل userDetail.vue برویم و از یک lifecycle hook به نام Created استفاده کنیم. در جلسات قبل به طور مفصل در مورد lifecycle hook ها صحبت کردیم بنابراین دوباره وارد این مسائل نمی شوم. من می خواهم یک listener را برای این کامپوننت ثبت کنم که از لحظه ایجاد این کامپوننت شروع به کار کند و از طرفی همانطور که می دانید created هنگام ساخته شدن کامپوننت اجرا می شود. بنابراین در مرحله اول EventBus را وارد این فایل می کنیم:

<script>
import { eventBus } from "../main";

export default {
  props: {
    myName: {
      type: String
    },
// بقیه کدها //

حالا Created را ایجاد کرده و می گوییم:

// بقیه کدها //
  methods: {
    switchName() {
      return this.myName
        .split("")
        .reverse()
        .join("");
    },
    resetName() {
      this.myName = "Amir";
      this.$emit("nameWasReset", this.myName);
    }
  },
  created() {
    eventBus.$on();
  }
};
</script>

دقت کنید که من از عمد قسمت methods را نیز در کد بالا آورده ام تا متوجه شوید که lifecycle hook ها در خارج از methods قرار می گیرند. اگر آن ها را درون methods تعریف کنید، انگار یک متد ساده و جدید برای خودتان تعریف کرده اید و دیگر lifecycle hook نیستند. زمانی که از on$ روی eventBus استفاده می کنیم، یعنی eventBus شروع به گوش کردن به event ها خواهد کرد بنابراین هر event ای که emit شود در اینجا تشخیص داده خواهد شد. On$ دو آرگومان می گیرد که اولین آرگومان همان event ای است که باید به آن گوش داده شود. آرگومان دوم نیز همان داده هایی خواهد بود که با event ارسال شده است بنابراین:

// بقیه کدها //
  created() {
    eventBus.$on("ageWasEdited", (age) => {
      this.userAge = age;
    });
  }
};
</script>

ageWasEdited نام همان custom event ما است که روی eventBus ارسال (emit) کرده بودیم بنابراین در اینجا هم می خواهیم به همان event گوش بدهیم. برای آرگومان دوم نیز می توانیم از یک تابع عادی استفاده کنیم (تابع بالا یک arrow function است – نسخه جدید توابع در ES6 – اما شما می توانید از یک تابع ES5 نیز استفاده کنید). این تابع آرگومانی می گیرد که نامش به دلخواه شماست (من آن را age گذاشته ام اما شما می توانید هر مقدار دیگری مانند data و غیره را انتخاب کنید) اما مقدارش همان مقداری است که با event پاس داده می شود و من می دانم که این مقدار همان سن کاربر است. نهایتا گفته ام که سن پاس داده شده را به عنوان this.userAge (استفاده از this یعنی سن کاربر در این کامپوننت، نه در EventBus) قرار بده.

حالا اگر به مرورگر بروید، کدها بدون مشکل کار می کنند! این روش، روش بهتری برای پاس دادن اطلاعات بین کامپوننت های خواهر و برادر است. برای اثبات اینکه داده ها به کامپوننت پدر نرفته و از آنجا منتقل نمی شوند، به فایل user.vue می رویم و Age را در آنجا نیز نمایش می دهیم:

// بقیه کدها //
    <button @click="changeName">Change my Name</button>
    <p>Name is {{ name }}</p>
    <p>Age is {{ age }}</p>
    <hr />
// بقیه کدها //
استفاده از busevent مشکل ما را حل می کند و بدون پاس دادن داده ها به کامپوننت پدر، اطلاعات را منتقل می نماید
استفاده از busevent مشکل ما را حل می کند و بدون پاس دادن داده ها به کامپوننت پدر، اطلاعات را منتقل می نماید

همانطور که در تصویر بالا مشخص است با کلیک روی دکمه Edit Age سن در دو کامپوننت برادر تغییر می کند (30) اما در کامپوننت پدر هنوز روی 27 مانده است.

کاری که ما در این جلسه انجام داده ایم state management یا مدیریت وضعیت برنامه است اما روشی که در این جلسه یاد گرفته ایم هنوز بهترین روش نیست. با اینکه این روش کار ما را ساده تر کرده است و برای برنامه های کوچک یا متوسط خوب کار می کند اما برای برنامه های بزرگ تر هنوز بهینه نیست و مدیریت state به این شکل باعث سردرگمی اعضای تیم توسعه شما می شود. فریم ورک Vue ابزار بسیار مناسب تری به نام VueX دارد که state management با آن بسیار راحت تر خواهد شد. ما هم در طول این دوره از این ابزار استفاده خواهیم کرد اما فعلا سراغ آن نمی رویم تا با مباحث بیشتری آشنا شویم.

نکته نهایی این است که شما می توانید از شیء eventBus به عنوان یک شیء مرکزی برای کل برنامه استفاده کنید. به طور مثال دوباره به main.js برگشته و می گوییم:

import Vue from 'vue'
import App from './App.vue'

export const eventBus = new Vue({
  methods: {
    changeAge(age) {
      this.$emit('ageWasEdited', age);
    }
  }
});

new Vue({
  el: '#app',
  render: h => h(App)
});

سپس به userEdit.vue می رویم و emit قبلی خودمان را کامنت می کنیم و به جایش از این متد استفاده می کنیم:

export default {
  props: ["userAge"],
  methods: {
    editAge() {
      this.userAge = 30;
      // this.$emit("ageWasEdited", this.userAge);
      // eventBus.$emit("ageWasEdited", this.userAge);
      eventBus.changeAge(this.userAge);
    }
  }
};
</script>

با این کار برنامه ما هنوز به طور سالم کار می کند و هیچ مشکلی نخواهیم داشت. بنابراین می بینید که eventBus (یا هر نام دیگری که برای این شیء Vue بگذارید) می تواند به عنوان یک نگهدارنده مرکزی برای متدها یا حتی data شما مورد استفاده باشد. مثلا شما می توانید age را به جای کامپوننت پدر، درون eventBus تعریف کرده و در سراسر برنامه از آن استفاده کنید.

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

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