8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Date Picker (Materialize CSS)のレイアウトをカスタマイズする

Posted at

TL; DR

Materialize CSSDate Picker において、日付が表示される部分のレイアウトを動的(dynamic)に変更できるようになる。

動機

カレンダーの表示をオプションで日本語化ができるのだが、レイアウトが酷すぎる。
after.png
これを日めくりカレンダー風に変更してみた。
after.png

datepicker.js

materialize.js(materialize.min.js)にコンポーネントやらなんやらの設定が詰まっている。が、これとは別にdatepicker.jsを読み込むとこちらの内容が優先されるようである(ドキュメントが見つけられなかったので「ようである」という表現)。

そこで、このファイルに変更を加えてゆく。

Datepicker._template

ピッカーのテンプレートは次のようになっていて、これをベースに JavaScript でレンダリングしている。しかし、class.datepicker-date-displayのコンテナが年(.year-text)と曜日・月・日(.date-text)の二つしかないので使いづらい。そこで、コンテナのタグをspanではなくdivにした上で年、月、日、曜日の四つに変更する。

<div class= "modal datepicker-modal">
  <div class="modal-content datepicker-container">
    <div class="datepicker-date-display">
      <span class="year-text"></span>
      <span class="date-text"></span>
    </div>
    <div class="datepicker-calendar-container">
      <div class="datepicker-calendar"></div>
      <div class="datepicker-footer">
        <button class="btn-flat datepicker-clear waves-effect" style="visibility: hidden;" type="button"></button>
        <div class="confirmation-btns">
          <button class="btn-flat datepicker-cancel waves-effect" type="button"></button>
          <button class="btn-flat datepicker-done waves-effect" type="button"></button>
        </div>
      </div>
    </div>
  </div>
</div>

_renderDateDisplay()

レンダリングはこのメソッドでなされるが、this.dateTextEl.innerHTML = `${day}, ${month} ${date}`;の部分が使いづらくしている諸悪の根源なので、ここを変更する。

上述の方針で変更したのが次のとおり。

diff の読み方 `*** 324,330 ***` :古い方の324行目から330行目は次の7行でこうなってますよ。 `--- 324,332 ---` :新しい方の324行目から332行目は次の9行でこうなってますよ。 `!`:古いのと新しいのと対応する行で違いがあります。 `+`:新しい方で追加されました。
diff -c datepicker.jp
***************
*** 324,330 ****
        let month = i18n.monthsShort[displayDate.getMonth()];
        let date = displayDate.getDate();
        this.yearTextEl.innerHTML = displayDate.getFullYear();
!       this.dateTextEl.innerHTML = `${day}, ${month} ${date}`;
      }
  
      /**
--- 324,332 ----
        let month = i18n.monthsShort[displayDate.getMonth()];
        let date = displayDate.getDate();
        this.yearTextEl.innerHTML = displayDate.getFullYear();
!       this.dateTextEl.innerHTML = displayDate.getDate();
!       this.dayTextEl.innerHTML = i18n.weekdaysShort[displayDate.getDay()];
!       this.monthTextEl.innerHTML = i18n.monthsShort[displayDate.getMonth()];
      }
  
      /**
***************
*** 751,756 ****
--- 753,760 ----
  
        this.yearTextEl = this.modalEl.querySelector('.year-text');
        this.dateTextEl = this.modalEl.querySelector('.date-text');
+       this.dayTextEl = this.modalEl.querySelector('.day-text');
+       this.monthTextEl = this.modalEl.querySelector('.month-text');
        if (this.options.showClearBtn) {
          this.clearBtn = this.modalEl.querySelector('.datepicker-clear');
        }
***************
*** 950,957 ****
      '<div class= "modal datepicker-modal">',
      '<div class="modal-content datepicker-container">',
      '<div class="datepicker-date-display">',
!     '<span class="year-text"></span>',
!     '<span class="date-text"></span>',
      '</div>',
      '<div class="datepicker-calendar-container">',
      '<div class="datepicker-calendar"></div>',
--- 954,963 ----
      '<div class= "modal datepicker-modal">',
      '<div class="modal-content datepicker-container">',
      '<div class="datepicker-date-display">',
!     '<div class="year-text"></div>',
!     '<div class="day-text"></div>',
!     '<div class="month-text"></div>',
!     '<div class="date-text"></div>',
      '</div>',
      '<div class="datepicker-calendar-container">',
      '<div class="datepicker-calendar"></div>',

カスタマイズ

sample.htmlでは以下の3箇所がいつもと違うところ
  • ①. カスタマイズしたdatepicker.jsを読み込む
  • ②. レイアウト用のCSSsample.cssを読み込む
  • ③. ピッカーの変更用sample.jsを読み込む
sample.html
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <!-- Compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <!-- Compiled and minified JavaScript -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
    <!-- カスタマイズされたdatepicker.jsとレイアウト用のCSSを読み込む -->
    <script type="text/javascript" src="datepicker.js"></script> <!-- ① -->
    <link rel="stylesheet" href="sample.css"> <!-- ② -->
  </head>
  <body>
    <input type="text" class="datepicker">
    <script type="text/javascript" src="sample.js"></script> <!-- ③ -->
  </body>
</html>
sample.cssで見た目の変更(解説省略)
sample.css
.datepicker-date-display { text-align:center; }
.year-text { font-size:2rem !important; }
.day-text, .month-text { font-size:3rem; }
.date-text { font-size:8rem !important; padding:2rem; }
sample.jsがカスタマイズの本丸
  • ①. ドキュメント(チュートリアル)そのまま
  • ②. i18nオプションを変更することで日本語化できる
  • ③. onDrawオプションはモーダルウィンドウが表示された後に呼ばれるので、ここでレイアウトを動的に変更する
  • ④. DOMの要素を取得して一旦除去する
  • ⑤. 目的に従ってレイアウトを再構成する。
    ここでは単純に順番を入れ替えているだけだが、デフォルトでは日にちのが表示されないので、date.appendChild(document.createTextNode('日'));などとして付け加えることもできる
sample.js
M.AutoInit(); //①
let options = {
  onDraw:function(e){ //③
  let panel = document.querySelector('.datepicker-date-display'); //④
  let year = e.yearTextEl.parentNode.removeChild(e.yearTextEl); //④
  let day = e.dayTextEl.parentNode.removeChild(e.dayTextEl); //④
  let month = e.monthTextEl.parentNode.removeChild(e.monthTextEl); //④
  let date = e.dateTextEl.parentNode.removeChild(e.dateTextEl); //④
  panel.appendChild(year); //⑤
  panel.appendChild(month); //⑤
  panel.appendChild(date); //⑤
  panel.appendChild(day); //⑤
},
  i18n:{ //②
    months:['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
    monthsShort:['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
    weekdays:['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'],
    weekdaysShort:['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'],
    weekdaysAbbrev:['','','','','','','']
  }
};
document.addEventListener('DOMContentLoaded', function() { //①
  var elems = document.querySelectorAll('.datepicker'); //①
  var instances = M.Datepicker.init(elems, options); //①
}); //①

補足

  • Materialize CSSのバージョンは1.0.0、レイアウトを目視で確認したのはPC版のChrome、Safari、Firefoxのみ

  • 上述では日本語ページ、英語ページがある場合など動的に変更する必要がある場合を想定してカスタマイズしているが、固定したレイアウトであればdatepicker.jsで変更してしまってもよい。

  • datepicker.jsGitHubjsディレクトリ にある

  • jsディレクトリには他にも buttons.jsやらtimepicker.jsやら個別の設定ファイルがあるので、同じ方針でカスタマイズできるかもしれない。

  • 上述のカスタマイズでは以下の3行が不要なのだが、ポイントとなる変更箇所に注力するため残してある

    323   let day = i18n.weekdaysShort[displayDate.getDay()];
    324   let month = i18n.monthsShort[displayDate.getMonth()];
    325   let date = displayDate.getDate();
    
8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?