とんたんの技術メモ

注)ただのメモです。

リアルタイムカウントダウンフッターの実装メモ

f:id:tontandesu:20190305031038j:plain こんな感じで記事中とフッター固定にリアルタイムカウントダウンを実装したのでその時のメモ。 あと、10秒くらいで、「現在あなたの他にN人が見ています」という表示に下から上にスライドで切り替わる機能も付いています。

HTML

## コード記入例
<p><countdown_views>{"message":"セール終了まで残り","limit":0,"vmin":10,"vmax":20,"infooter":false}</countdown_views></p>
<countdown_views>{"message":"セール終了まで残り","limit":0,"vmin":10,"vmax":20,"infooter":true}</countdown_views>

## パラメータ説明
message = カウントダウンの補足が入ります。
limit = 0を指定すると今日終了まで、1を指定すると1時間タイマー、2を指定すると2時間タイマー…
vmin = 現在の閲覧者数の最小値
vmax = 現在の閲覧者数の最大値(最小と最大の範囲でランダムに数字が入ります)
infooter = true: フッターに固定する, false: 固定しない

JS

window.addEventListener('load', function() {
  var _$ = jQuery || $;

  (() => {
    if(!_$('countdown_views').get(0)) return;

    let countdownAction = ($time, endTime, limit) => {
      let html = '';
      let startTime = new Date();
      let diff = endTime - startTime;
      let times = 24 * 60 * 60 * 1000;
      let day = Math.floor(diff / times);
      var hour = Math.floor(diff % times / (60 * 60 * 1000));
      var min = Math.floor(diff % times / (60 * 1000)) % 60;
      var sec = Math.floor(diff % times / 1000) % 60 % 60;

      if (diff > 0) {
        if (day > 0) html += `<span>${day}</span>日`;
        html += `<span>${('00' + hour).slice(-2)}</span>時間`;
        html += `<span>${('00' + min).slice(-2)}</span>分`;
        html += `<span>${('00' + sec).slice(-2)}</span>秒 `;
        $time.html(html);
        setTimeout(function(){
          countdownAction($time, endTime, limit);
        }, 10);
      } else {
        endTime = getEndTime(limit);
        countdownAction($time, endTime, limit);
      }
    };

    let getEndTime = (limit) => {
      let endTime;
      if (limit > 0) {
        endTime = new Date(Date.now() + limit * 60 * 60 * 1000);
      } else {
        let now = new Date();
        endTime = new Date(`${now.getFullYear()}/${now.getMonth() + 1}/${now.getDate()} 23:59:59`);
      }
      return endTime;
    }

    let setVcount = ($vcount, min, max) => {
      $vcount.text(Math.floor(Math.random() * (max + 1 - min)) + min);
    }

    _$('countdown_views').each((idx, elm) => {
      let $box = _$(elm);
      let json = _$.parseJSON($box.text());
      let idName = `wfcdv${idx}`;
      let vcIdName = `wfcdvc${idx}`;
      if (json.infooter) {
        $box.remove();
        _$('body').append(`
          <div class="wfcountdown_views wffooterfix">
            <div class="wflist">
              <div><p class="wfm">${json.message}</p><p id="${idName}" class="wft"></p></div>
              <div><p class="wfvm">現在あなたの他に<span id="${vcIdName}" class="wfcount"></span>人が見ています</p></div>
            </div>
          </div>
          `);
      } else {
        $box.replaceWith(`
        <div class="wfcountdown_views">
          <div class="wflist">
            <div><p class="wfm">${json.message}</p><p id="${idName}" class="wft"></p></div>
            <div><p class="wfvm">現在あなたの他に<span id="${vcIdName}" class="wfcount"></span>人が見ています</p></div>
          </div>
        </div>
        `);
      }
      let endTime = getEndTime(json.limit);
      let $time = _$(`#${idName}`);
      setTimeout(() => {
        countdownAction($time, endTime, json.limit);
      }, 10);

      let $vcount = _$(`#${vcIdName}`);
      setVcount($vcount, json.vmin, json.vmax);
      setInterval(() => {
        setVcount($vcount, json.vmin, json.vmax);
      }, 10000);
    });
  })();

})

SCSS

.wfcountdown_views {
  width: 100%;
  height: 95px;
  background: #3D3D3D;
  overflow: hidden;
  position:relative;
  line-height: 1.5;

  .wflist {
    display: flex;
    flex-direction: column;
    align-items: center;
    animation: slideToBottom 10s ease infinite .5s;

    div {
      width: 100%;
      height: 95px;
      background: #3D3D3D;
      color: #fff;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
    }

    div:first-child {
      z-index:-1;
      animation: image-change 10s ease infinite .5s;
    }
  }

  p {
    margin: 0;
  }

  .wfm {
    font-size: 14px;
  }

  .wfvm {
    font-size: 16px;

    .wfcount {
      color: #F6CF2B;
      font-weight: bold;
      font-size: 28px;
    }
  }

  .wft {
    font-size: 28px;

    span {
      color: #F6CF2B;
      font-weight: bold;
    }
  }

  &.wffooterfix {
    position: fixed;
    bottom: 0;
  }
}

@keyframes image-change {
  0%,50% {
     transform: translateY(0%);
   }
   80%,100% {
     transform: translateY(190px);
   }
 }

 @keyframes slideToBottom {
   0%,
   40% {
     -webkit-transform: translateY(0);
     transform: translateY(0);
   }
   45%,
   90% {
     -webkit-transform: translateY(-95px);
     transform: translateY(-95px);
   }
   95%,
   100% {
     -webkit-transform: translateY(-190px);
     transform: translateY(-190px);
   }
 }