Vue.jsを使ってカレンダーっぽいものを作ってみました。
全てが祝日かつ大安の素晴らしいカレンダーです。
なるほどHOLIDAYじゃねーの
ちなみに画面レイアウトはcssでdivにdisplay:flexを適用していい感じに並ぶようにしてます。
Vue.jsについて
調べるとMVVMフレームワークだとかの話が色々出てきますが、とりあえず今のところは
簡単にデータバインディングができたりカスタムタグっぽいもの(component)が作れたりするので
javascriptで動的なWebページを作りたい時とかに便利
ぐらいの認識です。
基本的な使い方は公式のガイドを読んだほうが早そうです。
Vue.jsを使ったところ
HTML側
<div id="calendar">
<div class="flex main">
<!-- 前月移動ボタン -->
<div class="headerItem shiftButton">
<div class="dateItem border table button" v-on:click="shift('back')">
<i class="fa fa-caret-left arrow middle" aria-hidden="true"></i>
</div>
</div>
<!-- 年月表示 -->
<div v-cloak class="headerItem monthYear">
<div class="dateItem border table">
<span class="middle">{{year}}年{{padLeft(month)}}月</span>
</div>
</div>
<!-- 次月移動 -->
<div class="headerItem shiftButton">
<div class="dateItem border table button" v-on:click="shift('next')">
<i class="fa fa-caret-right arrow middle" aria-hidden="true"></i>
</div>
</div>
</div>
<div v-cloak class="flex main">
<!-- 曜日 -->
<div class="weekList" v-for="date in weekList">
<div class="dateItem border">
<p>{{date}}</p>
</div>
</div>
</div>
<div v-cloak class="flex main">
<!-- 日付 -->
<div class="list" v-for="date in list">
<div class="dateItem border" v-bind:class="{ notThisMonth: date.isNotThisMonth }">
<p class="date">{{date.date}}</p>
<p class="six">{{date.six}}</p>
<p class="anniv">{{date.anniv}}</p>
</div>
</div>
</div>
</div>
Vueオブジェクトの定義(Javascript)
new Vue({
el: '#calendar',
data: {
year:year,
month:month,
weekList: ['日','月','火','水','木','金','土'],
list: row,
},
methods: {
shift:function(val){
if('back'===val){
this.month = (this.month===1)?12:this.month-1;
this.year = (this.month===12)?this.year-1:this.year;
}else{
this.month = (this.month===12)?1:this.month+1;
this.year = (this.month===1)?this.year+1:this.year;
}
this.list = updateRow(this.year,this.month);
},
padLeft:function(val){
return padLeft(val);
}
}
});
今回使用したVue.jsの機能
データバインディング
Vueと連動している要素の中に、Vueオブジェクト内の変数名を書いておくとその値が画面に描画されます。
変数名を中括弧{}2つで囲うのが基本的な書き方です。
例えば今回の年月の表示部分には
<span class="middle">{{year}}年{{padLeft(month)}}月</span>
とか書いてます。
変数名はVueオブジェクトの中に定義した連想配列data内の変数名と対応しています。
↓ javascript側ソースのこの部分。
data: {
year:year,
month:month,
…
…
},
ちなみに中括弧の中には変数名だけでなく、メソッドとか計算式も書けます。
今回の場合も月の値を持つmonthを引数にpadLeftメソッドを呼び出してその戻り値を画面にバインドしてます。
{{padLeft(month)}}
こう書くと、jsの
methods: {
padLeft:function(val){
return padLeft(val);
}
}
ここが呼ばれます。
画面のちらつき防止 v-cloak
これをデータをバインドする要素の親要素に記述しておくと、バインド時の画面のちらつきを抑える事ができます。
これが無いとたまに一瞬バインド前の文字列({{year}}年{{padLeft(month)}}月)が画面にそのまま表示されて
若干格好悪いことになったりするので意外と重要です。
クリックイベントの設定 v-on:click
Vueと連動しているDOM要素に対してクリックイベントを設定します。
今回の場合は前月・次月移動ボタンにv-on:click="shift('next')" というような形で書いてます。
このshiftというメソッドはVueオブジェクトの中のmethods: の中に定義されています。
メソッドに引数を設定することもできます。今回の場合は文字列を渡しています。
ループ処理 v-for
ループの回数分だけDOM要素を動的に生成してくれます。
<div class="weekList" v-for="date in weekList">
<div class="dateItem border">
<p>{{date}}</p>
</div>
</div>
この場合はVueオブジェクト内の配列weekListの中身を変数dataとして一つずつ取り出し、dataの中身を表示しています。
weekList: ['日','月','火','水','木','金','土']
配列の中身は今回こんな感じなので、
<div class="dateItem border">
<p>{{date}}</p>
</div>
の部分が7つ生成されます。
クラスの切り替え v-bind:class
v-bind:classを使用すると、Vueオブジェクトのデータの中身によってDOMに適用させるclassを切り替えることができます。
<div class="list" v-for="date in list">
<div class="dateItem border" v-bind:class="{ notThisMonth: date.isNotThisMonth }">
<p class="date">{{date.date}}</p>
<p class="six">{{date.six}}</p>
<p class="anniv">{{date.anniv}}</p>
</div>
</div>
この場合、変数date内にあるisNotThisMonthがtrueの場合に、対象のDOM要素にnotThisMonthクラスが追加されます。
今回はカレンダーの背景がグレーになっている日付部分にこのnotThisMonthクラスが適用されています。
おわり
とりあえずVue.jsを見様見真似で使ってみましたが、もっと良い書き方ありそう。
引き続き精進します。