پیاده سازی toast با nuxt

پیاده سازی toast با nuxt

در این مقاله قرار است با تکنیک پیاده سازی یک toast message ساده آشنا شویم، این موضوع علاوه بر جنبه تکنیکی کار، جنبه آموزشی نیز دارد. توجه کنید که علاوه بر کد، توضیحات متنی مقاله را هم مطالعه کنید تا نکات اصلی از چشم شما دور نماند. قسمت مهم کار پیاده سازی composable کلی برای مدیریت پیام های toast است و بقیه ماجرا صرفا استایل دهی و استفاده صحیح از composable مربوطه است.

یدالله ضیاالدینی
شنبه ۱۸-آذر-۱۴۰۲
طرز استفاده!

ابتدا بد نیست ببینیم چه چیزی قرار است پیاده کنیم.

 const { showToast } = useToast();
 
 showToast({ type: ToastEnum.success, message: "ایمیل حاوی لینک بازنشانی برای شما ارسال شد." });
 //بدون typescript
 showToast({ type: 'success', message: "ایمیل حاوی لینک بازنشانی برای شما ارسال شد." });
مرحله اول پیاده سازی یک global ref
برای پیاده سازی global ref دو روش وجود داره:
//روش اول 
export const useToast = () => {
    const toastRef = useState('--toast--', () => ({ show: false, message: '', type: "info" }));
    return { toastRef };
}

//روش دوم
const toastRef = ref({ show: false, message: "" , type: "info" });
export const useToast = () => {
    return { toastRef };
}
توجه داشته باشید! روش اول باید حتما با nuxt استفاده شود اگر از روش دوم روی حالت SSR استفاده کنید، state بین تمام کاربران به اشتراک گذاشته می شود.
اضافه کردن متدهای showToast و close
export const useToast = () => {
  const toastRef = useState('--toast--', () => ({ show: false, message: "", type: "info" }));
  const close =() => {
      toastRef.value = { ...toastRef.value, show: false }
  }
  const showToast = ({ message, type }) => {
      toastRef.value = { message, type, show: true };
      setTimeout(()=>{
        close();
      },3000)
  }
  return { showToast, toastRef };
}
حذف timeOut با استفاده از useDebounceFn (اختیاری)
دستور نصب npm i @vueuse/core
import { useDebounceFn } from '@vueuse/core'
export const useToast = () => {
  const toastRef = useState('--toast--', () => ({ show: false, message: "", type: "info" }));
  const debounceClose = useDebounceFn(() => {
    toastRef.value = { ...toastRef.value, show: false }
  }, 3000)
  const showToast = ({ message, type }) => {
      toastRef.value = { message, type, show: true };
      debounceClose()
  }
  return { showToast, toastRef };
}
اضافه کردن typescript (اختیاری)
export enum ToastEnum {
  info = 'info',
  success = 'success',
  warning = 'warning',
  error = 'error'
}
interface Toast {
    message: string;
    type: ToastEnum;
    show: boolean;
}
export const useToast = () => {
    const toastRef = useState<Toast>('--toast--', () => ({ show: false, message: '', type: ToastEnum.info }));
    const debounceClose = useDebounceFn(() => {
        toastRef.value = { ...toastRef.value, show: false }
    }, 3000)
    const showToast = ({ message, type = ToastEnum.info }: { message: string, type: ToastEnum }) => {
        toastRef.value = { message, type, show: true };
        debounceClose();
    }
    return { showToast, toastRef };
}
خب اصل پیاده سازی کامل شد! فقط کافیه یک کامپوننت بسازیم که از message و type استفاده کنه و خودش رو با true و false شدن مقدار show, وفق بده .
پیاده سازی کامپوننت مربوطه
ما از GSAP برای پیاده سازی انیمیشن کامپوننت استفاده کرده ایم، اما شما می توانید از هر روشی که دوست دارید استفاده کنید.
<template>
  <div
    ref="target"
    class="invisible fixed bottom-0 right-1/2 transform translate-x-1/2 p-3 rounded-md"
    :class="`bg-${toastRef.type} text-white`"
  >
    {{ toastRef.message }}
  </div>
</template>
<script setup lang="ts">
  // safe list in tailwind.config or just comment them here bg-info bg-success bg-warning bg-error
  import gsap from "gsap";
  const { toastRef } = useToast();
  const target = ref<HTMLElement | null>(null);
  let animation: any;
  const setAnimation = (): void => {
    animation = gsap.to(unref(target), {
      autoAlpha: 1,
      bottom: 80,
      ease: "power4",
      paused: true,
      duration: 0.5,
    });
  };
  onMounted(() => {
    setAnimation();
    if (unref(toastRef).show) {
      animation.play();
    }
  });
  watch(toastRef, (value) => {
    if (value.show) {
      animation.play();
    } else {
      animation.reverse();
    }
  });
</script>

صدا زدن کامپوننت در app.vue
<template>
  <div>
      <nuxt-layout>
        <nuxt-page></nuxt-page>
      </nuxt-layout>
    <app-toast></app-toast>
  </div>
</template>
هر کامپوننت یا composable ای که در app.vue فراخوانی می کنید، بصورت global اضافه می شود بنابراین به طول bundle اصلی پروژه اضافه می کند!
ما در کامپوننت ای که پیاده سازی کردیم از GSAP هم استفاده کردیم بنابراین اسکریپت GSAP هم به باندل پروژه اضافه می شود، در ادامه راه حل مناسب جهت بهینه سازی ارائه شده است.
ابتدا مطمئن شوید که کامپوننت appToast ای که پیاده سازی کردیم با توجه به تنظیمات nuxt حتما autoImport باشد
<template>
  <div>
      <nuxt-layout>
        <nuxt-page></nuxt-page>
      </nuxt-layout>
    <lazy-app-toast v-if="toastRef.show"></lazy-app-toast>
  </div>
</template>

<script lang="ts" setup>
const { toastRef } = useToast();
</script>

توجه کنید که چون کامپوننت toast رو تا زمانی که show=true نشده نیاز نداریم می تونیم از این روش استفاده کنیم، حتما v-if رو فراموش نکنید. این کار باعث می شود هنگام باندل پروژه توسط vite یا webpack یک chunk جداگانه ساخته شود که از chunk اصلی پروژه مجزاست.

برای اینکه راستی آزمایی کنید که کار درست انجام شده، می تونید وقتی که برای اولین بار toast رو نمایش می دهید، از تب network مرورگر ببینید که اسکریپت مربوط به کامپوننت، پس از نمایش، شروع به دانلود می کند.

نکته پایانی

پیاده سازی انجام شده در این مقاله بصورت ویدئویی در

دوره آموزش nuxt3

ویدئوی شماره ۳۴ کامل توضیح داده شده است، اگر نکات ظریف این مقاله توجه شما را جلب کرده است، می توانید برای تکمیل دانش خود از این دوره بهره ببرید.

کلیه حقوق این وب سایت متعلق به آکادمی لند می باشد و هرگونه کپی برداری از محصولات غیر مجاز می باشد.
box iconbox iconارتباط با ماتصویر نماد