<div class="other-35" id="js-other-35">
    <div class="section"><button class="button is-primary" id="js-other-35-button">プレゼント取得</button></div>
</div>
<div class="modal other-35__modal" id="js-other-35-modal">
    <div class="modal-background"></div>
    <div class="modal-content">
        <div class="box other-35__modal-box">
            <div class="other-35__modal-loader" id="js-other-35-loader"></div>
            <div class="other-35__modal-close">
                <div class="content has-text-centered">
                    <p>取得が完了しました</p>
                    <p><button class="button" id="js-other-35-close">閉じる</button></p>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="../../js/script.js"></script>
.other-35#js-other-35
  .section
    button.button.is-primary#js-other-35-button プレゼント取得

//- ローディングモーダル
.modal.other-35__modal#js-other-35-modal
  .modal-background
  .modal-content
    .box.other-35__modal-box
      .other-35__modal-loader#js-other-35-loader
      .other-35__modal-close
        .content.has-text-centered
          p 取得が完了しました
          p
            button.button#js-other-35-close 閉じる

script(src=path('/js/script.js'))
{
  "text": "テキストが入ります。テキストが入ります。テキストが入ります。"
}
  • Content:
    'use strict';
    import lottie, { AnimationItem } from 'lottie-web';
    
    export const other35 = () => {
      const other = new Other35();
      other.init();
    };
    
    class Other35 {
      el: HTMLElement;
      loaderEl: HTMLElement;
      buttonEl: HTMLElement;
      modalEl: HTMLElement;
      closeEl: HTMLElement;
      lottieDataUrl: string;
      lottie: AnimationItem;
      // lottie: any;
      isLoading: boolean;
      isLoadingAnim: boolean;
    
      constructor() {
        this.el = document.getElementById('js-other-35');
        this.loaderEl = document.getElementById('js-other-35-loader');
        this.buttonEl = document.getElementById('js-other-35-button');
        this.modalEl = document.getElementById('js-other-35-modal');
        this.closeEl = document.getElementById('js-other-35-close');
        if (location.origin === 'https://zakzakst.github.io') {
          // GitHubの場合
          this.lottieDataUrl =
            '/parts/img/components/others/other35/present-2.json';
        } else {
          // ローカル環境の場合
          this.lottieDataUrl = '/img/components/others/other35/present-2.json';
        }
        this.isLoading = false;
        this.isLoadingAnim = true;
      }
      /**
       * 初期化
       */
      init() {
        if (!this.el) return;
        this.lottieInit();
        this.onClickButton();
        this.onClickClose();
      }
    
      /**
       * lottie 初期化
       */
      lottieInit() {
        this.lottie = lottie.loadAnimation({
          container: this.loaderEl,
          renderer: 'svg',
          loop: false,
          autoplay: false,
          path: this.lottieDataUrl,
        });
        // 何倍かの数値を設定。1は通常の速度
        this.lottie.setSpeed(1.5);
        // ループ完了時の処理
        // @ts-ignore
        this.lottie.onComplete = async () => {
          if (!this.isLoading) {
            // ロード完了している場合
            if (this.isLoadingAnim) {
              console.log('ループアニメーション終了');
              // 一度完了アニメーションを表示
              this.lottieFinishAnim();
              this.isLoadingAnim = false;
            } else {
              console.log('完了アニメーション終了');
              await this.delay(300);
              this.setModalLoading(false);
            }
          } else {
            this.lottieLoopAnim();
          }
        };
      }
    
      /**
       * 開始アニメーション表示
       */
      lottieStartAnim() {
        this.lottie.playSegments([0, 20], true);
      }
    
      /**
       * ループアニメーション表示
       */
      lottieLoopAnim() {
        this.lottie.playSegments([21, 90], false);
      }
    
      /**
       * 完了アニメーション表示
       */
      lottieFinishAnim() {
        this.lottie.playSegments([91, 150], false);
      }
    
      /**
       * 取得ボタンクリック時の挙動
       */
      onClickButton() {
        this.buttonEl.addEventListener('click', async () => {
          if (this.isLoading) return;
          this.isLoading = true;
          this.isLoadingAnim = true;
          this.setModalLoading(true);
          this.showModal();
          this.lottieStartAnim();
          console.log('ロード開始');
          await this.randomDelay(1000, 6000);
          console.log('ロード完了');
          this.isLoading = false;
        });
      }
    
      /**
       * 閉じるボタンボタンクリック時の挙動
       */
      onClickClose() {
        this.closeEl.addEventListener('click', async () => {
          this.hideModal();
        });
      }
    
      /**
       * 指定の秒数待つ
       * @param ms 待つミリ秒
       * @returns Promiseインスタンス
       */
      delay(ms: number = 1000) {
        return new Promise((resolve) => {
          return setTimeout(resolve, ms);
        });
      }
    
      /**
       * ランダムな秒数待つ
       * @param minMs 待つミリ秒(最小値)
       * @param maxMs 待つミリ秒(最大値)
       * @returns Promiseインスタンス
       */
      randomDelay(minMs: number = 1000, maxMs: number = 1000) {
        const defaultDelay = 1000;
        const delay =
          minMs > maxMs
            ? defaultDelay
            : Math.random() * (maxMs + 1 - minMs) + minMs;
        console.log(`ランダムな秒数待つ:${delay}ms`);
        return new Promise((resolve) => {
          return setTimeout(resolve, delay);
        });
      }
    
      /**
       * モーダルを表示
       */
      showModal() {
        this.modalEl.classList.add('is-active');
      }
    
      /**
       * モーダルを非表示
       */
      hideModal() {
        this.modalEl.classList.remove('is-active');
      }
    
      /**
       * モーダルのロード状態を設定する
       * @param loading ロード中かどうか(trueでロード中)
       */
      setModalLoading(loading: boolean) {
        if (loading) {
          this.modalEl.classList.add('is-loading');
        } else {
          this.modalEl.classList.remove('is-loading');
        }
      }
    }
    
  • URL: /components/raw/other35/other35-2.ts
  • Filesystem Path: src/components/others/21_40/other35/other35-2.ts
  • Size: 4.5 KB
  • Content:
    $BLOCK_NAME: '.other-35';
    
    // 変数
    
    #{ $BLOCK_NAME } {
      &__modal-box {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 240px;
        height: 240px;
        margin: auto;
      }
    
      &__modal-loader {
        display: none;
        @at-root #{ $BLOCK_NAME }__modal.is-loading & {
          display: block;
        }
      }
    
      &__modal-close {
        @at-root #{ $BLOCK_NAME }__modal.is-loading & {
          display: none;
        }
      }
    }
    
  • URL: /components/raw/other35/other35.scss
  • Filesystem Path: src/components/others/21_40/other35/other35.scss
  • Size: 435 Bytes
  • Content:
    'use strict';
    import lottie from 'lottie-web';
    
    export const other35 = () => {
      const other = new Other35();
      other.init();
    };
    
    class Other35 {
      el: HTMLElement;
      loaderEl: HTMLElement;
      buttonEl: HTMLElement;
      modalEl: HTMLElement;
      closeEl: HTMLElement;
      lottieDataUrl: string;
      lottie: any;
      loaderInstanceName: string;
      isLoading: boolean;
      isLoadingAnim: boolean;
    
      constructor() {
        this.el = document.getElementById('js-other-35');
        this.loaderEl = document.getElementById('js-other-35-loader');
        this.buttonEl = document.getElementById('js-other-35-button');
        this.modalEl = document.getElementById('js-other-35-modal');
        this.closeEl = document.getElementById('js-other-35-close');
        if (location.origin === 'https://zakzakst.github.io') {
          // GitHubの場合
          this.lottieDataUrl = '/parts/img/components/others/other35/present.json';
        } else {
          // ローカル環境の場合
          this.lottieDataUrl = '/img/components/others/other35/present.json';
        }
        this.loaderInstanceName = 'other-35-loader';
        this.isLoading = false;
        this.isLoadingAnim = true;
      }
    
      /**
       * 初期化
       */
      init() {
        if (!this.el) return;
        this.lottieInit();
        this.onClickButton();
        this.onClickClose();
      }
    
      /**
       * lottie 初期化
       */
      lottieInit() {
        this.lottie = lottie.loadAnimation({
          container: this.loaderEl,
          renderer: 'svg',
          loop: false,
          autoplay: false,
          path: this.lottieDataUrl,
          // アニメーションインスタンスに名前を渡して、後でlottieコマンドで参照することができる
          name: this.loaderInstanceName,
          initialSegment: [0, 100],
        });
        // 何倍かの数値を設定。1は通常の速度
        this.lottie.setSpeed(2.5, this.loaderInstanceName);
        // ループ完了時の処理
        this.lottie.onComplete = async () => {
          if (!this.isLoading) {
            // ロード完了している場合
            if (this.isLoadingAnim) {
              console.log('ループアニメーション終了');
              // 一度完了アニメーションを表示
              this.lottieFinishAnim();
              this.isLoadingAnim = false;
            } else {
              console.log('完了アニメーション終了');
              await this.delay(300);
              this.setModalLoading(false);
            }
          } else {
            this.lottieLoopAnim();
          }
        };
      }
    
      /**
       * ループアニメーション表示
       */
      lottieLoopAnim() {
        this.lottie.playSegments([0, 100], true);
      }
    
      /**
       * 完了アニメーション表示
       */
      lottieFinishAnim() {
        this.lottie.playSegments([101, 186], true);
      }
    
      /**
       * 取得ボタンクリック時の挙動
       */
      onClickButton() {
        this.buttonEl.addEventListener('click', async () => {
          if (this.isLoading) return;
          this.isLoading = true;
          this.isLoadingAnim = true;
          this.setModalLoading(true);
          this.showModal();
          this.lottieLoopAnim();
          console.log('ロード開始');
          await this.randomDelay(5000, 10000);
          console.log('ロード完了');
          this.isLoading = false;
        });
      }
    
      /**
       * 閉じるボタンボタンクリック時の挙動
       */
      onClickClose() {
        this.closeEl.addEventListener('click', async () => {
          this.hideModal();
        });
      }
    
      /**
       * 指定の秒数待つ
       * @param ms 待つミリ秒
       * @returns Promiseインスタンス
       */
      delay(ms: number = 1000) {
        return new Promise((resolve) => {
          return setTimeout(resolve, ms);
        });
      }
    
      /**
       * ランダムな秒数待つ
       * @param minMs 待つミリ秒(最小値)
       * @param maxMs 待つミリ秒(最大値)
       * @returns Promiseインスタンス
       */
      randomDelay(minMs: number = 1000, maxMs: number = 1000) {
        const defaultDelay = 1000;
        const delay =
          minMs > maxMs
            ? defaultDelay
            : Math.random() * (maxMs + 1 - minMs) + minMs;
        console.log(`ランダムな秒数待つ:${delay}ms`);
        return new Promise((resolve) => {
          return setTimeout(resolve, delay);
        });
      }
    
      /**
       * モーダルを表示
       */
      showModal() {
        this.modalEl.classList.add('is-active');
      }
    
      /**
       * モーダルを非表示
       */
      hideModal() {
        this.modalEl.classList.remove('is-active');
      }
    
      /**
       * モーダルのロード状態を設定する
       * @param loading ロード中かどうか(trueでロード中)
       */
      setModalLoading(loading: boolean) {
        if (loading) {
          this.modalEl.classList.add('is-loading');
        } else {
          this.modalEl.classList.remove('is-loading');
        }
      }
    }
    
  • URL: /components/raw/other35/other35.ts
  • Filesystem Path: src/components/others/21_40/other35/other35.ts
  • Size: 4.6 KB

参考