Help us understand the problem. What is going on with this article?

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

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();
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした