Dandy Now!
  • [Vue.js] 고민 끝에 찾은 "vue3-toastify"를 이용한 토스트 알림 Custom 스타일-나만의-적용 방법
    2023년 09월 20일 15시 56분 38초에 업로드 된 글입니다.
    작성자: DandyNow
    728x90
    반응형

    1. "vue3-toastify" 오 이거 괜찮은데?!

    vue3 프로젝트에 적용할 토스트 라이브러리를 찾다가 npm에서 vue3-toastify 발견했다. 디자인, 애니메이션, 기능도 훌륭했고 문서도 제공되고 있었다.

    공식 페이지 : https://vue3-toastify.js-bridge.com/

     

    2. 알림의 종류에 따라 다른 스타일을 적용하고 싶은데 어떻게 하는 거지?

    "경고, 심각, 위험"이라는 3가지 상태에 대한 토스트 알림을 주고자 했다. 각 상태에 따라 각각 다른 사용자 경험을 주고 싶었고 백그라운드 컬러를 다르게 하는 방식을 생각했다. 그런데 그런 커스텀한 스타일은 어떻게 주는 거지??

    2.1. 시도

    공식 문서에서 "How to style"라는 페이지에서 힌트를 얻을 수 있을 것 같았다. 해당 문서를 참조해 root 스타일을 지정하고 관련 클래스를 오버라이딩하는 방식으로 진행해 보았으나 아무런 변화도 경험하지 못했다. 커스텀하게 적용한 scss의 실행 순서가 vue3-toastify 라이브러리의 로딩 순서보다 빨라서가 아닐까 하는 추측을 하고 있다.

    2.2. 다른 아이디어

    webpack에서 라이브러리의 로딩 순서를 제어하는 방식은 여간 복잡한 일이 아니어 보였다. 그리고 멀쩡한 다른 기능들에도 영향을 끼칠 수 있는 리스크도 있었다. 그래서 더 간편한 다른 방식을 찾아보기로 했다.  공식 문서"How to style"의 끝에 "Passing css classes to component"라는 주제가 있었다. GlobalProps에 스타일을 전달하는 방법이 안내되어 있었다.

     

    3. 템플릿 리트럴과 GlobalProps에 스타일 전달하여 커스텀 스타일 적용 성공!

    아래의 리스트와 같이 스타일과 관련하여 5개의 옵션에 클래스를 지정할 수 있었다.

    • style: inline style applied to the container
    • containerClassName: applied to the container
    • toastClassName: applied on the toast wrapper
    • bodyClassName: applied on the toast body
    • progressClassName: applied on the progress bar

    진행 중인 프로젝트에는 토스트 전체의 백그라운드 컬러를 변경하면 되었기 때문에 "toastClassName" 옵션에 커스텀 클래스를 적용하고, 동적 적용을 위해 템플릿 리트럴을 사용하였다.

    하지만 이것 만으로는 원하는 결과를 얻을 수 없었다. 적용하고자 하는 클래스를 v-global 처리하고 클래스의 각 스타일 속성들 마다 !important를 해주어야 했다.

    <script>
    // (생략)
    import ToastMsg from '@/components/fragments/ToastMsg' // 임의로 작성한 토스트 컴포넌트
    import { toast } from 'vue3-toastify' // vue3-toastify 라이브러리
    export default {
      // (생략)
      data() {
        return {
          toastClassNameColorLevel: 'toast-color-level-danger' // toastClassName에 적용될 클래스명. 이 값을 변경하여 원하는 스타일(경계, 위험, 심각)을 적용할 수 있음.
        }
      },
      methods: {
        notify(trueData, FalseData) {
          // 화면에 렌더링된 토스트 중 필요 없는 토스트 제거
          FalseData.forEach((el) => {
            toast.remove(el)
          })
          // 토스트 생성
          trueData.forEach((el) => {
            toast(ToastMsg, {
              autoClose: false,
              dangerouslyHTMLString: true,
              position: toast.POSITION.TOP_RIGHT,
              transition: toast.TRANSITIONS.SLIDE,
              data: el,
              toastId: el.alarmType,
              toastClassName: `${this.toastClassNameColorLevel}` // 이 부분에 커스텀 스타일을 템플릿 리트럴을 이용해 동적으로 적용함
            })
          })
        }
      }
    }
    </script>
    <style scoped lang="scss">
    /* 토스트 기본 스타일 */
    ::v-global(.Toastify__toast-container) {
      margin-left: 285px !important;
      width: calc(100% - 320px) !important;
    }
    
    /* 토스트 닫기 버튼 스타일 */
    ::v-global(.Toastify__close-button > svg) {
      color: #fff !important;
    }
    
    /* 아래의 3종류의 클래스를 동적으로 변경 적용하고자 하였음 */
    /* 경계 레벨 스타일 */
    ::v-global(.toast-color-level-boundary) {
      --boundary: #ffb400;
      background: var(--boundary) !important;
      color: #fff !important;
    }
    
    /* 심각 레벨 스타일 */
    ::v-global(.toast-color-level-serious) {
      --serious: #ff6b00;
      background: var(--serious) !important;
      color: #fff !important;
    }
    
    /* 위험 레벨 스타일 */
    ::v-global(.toast-color-level-danger) {
      --danger: #b70000;
      background: var(--danger) !important;
      color: #fff !important;
    }
    </style>

     

    728x90
    반응형
    댓글