「Hellow Vue.js」の続きです。前回はVue.jsを読み込んで、「こんにちは びゅう!」という文字を表示しました。しかしながら、これだけならjQueryや生JSでもできるわけなので、もう少し進めてみる。
基本編として、チュートリアルでまず目についた「イベント」「分岐」「ループ」をやってみた。それでは、どうぞ!
※目次:
※参考:前回の記事
三大フレームワークとかSPAとか仮想DOMとかわかりにくかったのでHellow Vue.jsしてみた! - クモのようにコツコツと
Vue.jsのディレクティブ
Vue.jsには「ディレクティブ」という独自の属性があります。頭にv-
が付くのが特徴です。
<!--書式--> <div v-hoge="属性値">コンテンツ<div> <!--例--> <div v-show="age >= 20">大人ですね</div>
チュートリアルによると…
ディレクティブの仕事は、属性値の式が変化したときに、リアクティブに副作用を DOM に適用することです。
前回の記事で触れたように「リアクト」は反応する、という意味。属性値の式の結果に反応してDOMの内容を変化させます。
代表的な例としてはイベント、分岐、ループがあります。「JSの基本-後編」で触れたイベントと分岐、ループと似たディレクティブ名が付いているのでイメージしやすいと思います。
※参考:JSのイベント、分岐、ループ
【JSの基本-後編】書ける前に読む!HTML、CSS、JSの書式-5 - クモのようにコツコツと
イベント(v-on)
Vue.jsのイベントのディレクティブはv-on
です。
チュートリアルを参考にいくつか作ってみました。
こちらはチュートリアルの一番最初にあるカウントアップの事例を改造しています。
属性値が式
「3 年目の浮気ぐらい大目に見てよ」というテキストの下に「馬鹿いってんじゃないわ」というボタンがありますね。これをクリックすると「3 年目」の数字がカウントアップしていきます。ほんと、馬鹿いってんじゃないですよね。
※参考:ちなみに元ネタはコチラ…
https://youtu.be/-TuFqVLDxZU
さて、このカウントアップはどのような仕組みになっているのか見ていきましょう。まずはHTML
<div id="payappa"> <p> {{ counter }} 年目の浮気ぐらい大目に見てよ</p> <button v-on:click="counter += 1">馬鹿いってんじゃないわ</button> </div>
- 一番外側がid
#payappa
のdiv要素。 - 中にp要素があり、「年目」の前には前回のHellow Vueと同じく波括弧2つ
{{ }}
で囲ったcounter
がある。 - その下のbutton要素の中には
v-on:click="counter += 1"
がある。
v-on
は「イベント」のディレクティブです。続く:hoge
は「キー修飾子」といい:click
はクリックイベントです。属性値はcounter
に1加算するという式が書いてあります。
次はJSを見ていきましょう。
var payappa = new Vue({ el: '#payappa', data: { counter: 3 } })
- 変数
payappa
でVue
インスタンスを作成。引数のに連想配列が入っている。(波括弧{ }
ブロック) el
キーの値でid#payappa
の要素と紐づいている。data
キーの値が入れ子の連想配列になっている- 入れ子の中の
counter
キーの値に3
が入る。
counter
に3
が入ることで「3年目」になり、v-on:click
のbutton要素をクリックするたびにcounter
の数値が1ずつカウントアップするわけです。
メソッドイベントハンドラ
v-on:click
の属性値の中に毎回式を書くのは再利用性が低く、複雑なコンテンツを作ることができません。
そこで、属性値にはイベントハンドラのメソッド名のみを書くほうが多くなってきそうです。こんな感じです。
「押してちょ」というボタンを押すと「こんにちは びゅう!」というアラートが出ました。
コードを見ていきましょう。HTMLはこちら
<div id="btn"> <button v-on:click="aisatsu">押してちょ</button> </div>
- 外側はid名
#btn
のdiv要素 - button要素の属性は
v-on:click
で属性値はaisatsu
HTMLはシンプルですね!属性値のaisatsu
がイベントハンドラのメソッド名です。
では、JSを見ていきましょう。
var btn = new Vue({ el: '#btn', data: { name: 'びゅう' }, methods: { aisatsu: function () { alert("こんにちは " + this.name + '!') } }
- 変数
btn
にVue
インスタンスを作成。中は連想配列{ }
el
キーで#btn
の要素と紐づくdata
キーの値は入れ子の連想配列- 入れ子の
name
キーの値はびゅう
methods
キーの値は連想配列- 入れ子の
aisatsu
キーの中に無名関数 - 無名関数の中にはアラートで「こんにちは」と
name
の値と「!」を合わせる
data
キーまでは最初の事例と同じ構成ですね。次のmethods
キーでメソッドを作ります。aisatu
がメソッド名です。アラートの引数の中でname
キーの文字列を呼び出しています。
インラインメソッドハンドラ
次は「インラインメソッドハンドラ」という事例です。
「いま何時(なんどき)でっか?」と質問していますので、今の時間帯に該当する「朝」「昼」「夜」のボタンを押してください。朝は「おはよう」、昼は「こんにちは」、夜は「こんばんは」という挨拶が頭につきます。
コードを見ていきます。まずHTML
<p>今何時(なんどき)でっか?</p> <div id="btn"> <button v-on:click="say('おはようございます')">朝だ</button> <button v-on:click="say('こんにちは')">昼だ</button> <button v-on:click="say('こんばんは')">夜だ</button> </div>
- ボタンが3つに増えました。
v-on:click
の属性値はsay()
メソッド。 - 「朝」ボタンの
say()
メソッドの引数は「おはようございます」。 - 「昼」ボタンの
say()
メソッドの引数は「こんにちは」。 - 「夜」ボタンの
say()
メソッドの引数は「こんばんは」。
アラートの頭の挨拶はきっとこの引数を読み込んでいるに違いない、と想像できますね。
ではJSを見てみましょう。
var btn = new Vue({ el: '#btn', data: { name: ' びゅう' }, methods: { say: function (message) { alert(message + this.name + '!') } } })
先ほどのメソッドイベントハンドラととてもよく似ていますね。違うのはmethods
キーの中のsay
キーの部分です。
methods
キーの値が連想配列でメソッドを設定する。say
キーの値が無名関数で引数はmessege
。- アラートの中で
messege
と上のdata
キーのname
を呼び出して「!」と合わせている。
これでHTMLのsay()
メソッドの引数の「おはようございます」などの文字列を読み込んでアラート表示しているわけです。
分岐(v-show、v-if)
次は「分岐」です。Vue.jsの分岐のディレクティブはv-show
とv-if
があります。
こちらもチュートリアルを参考にいくつか作ってみました。
v-show
v-show ディレクティブの事例です。v-showは条件によって表示する、しないを判定します。
一見ただのテキストが表示されているだけですね。なんて書いてありますか?実はこのテキスト、見る時間帯によって内容が変わります。 日中は「こんにちは。びゅう!」、18時より遅い時間に見ると「こんにちは。いや、こんばんは。びゅう!」となります。(0時過ぎると「こんにちは」に戻るんですけどね。。) どんな仕掛けになっているのでしょう。まずはHTML
<p id="app"> こんにちは。 <span v-show="Hours >= 18">いや、こんばんわ。</span> {{ message }} </p>
- id
#app
のdiv要素の中にspan要素がある。 - span要素にはディレクティブ
v-show
属性があり、属性値はHours >= 18
という条件式。 *二重波括弧{{ }}
でmassage
を読み込む。
JSを見ていきましょう。
//日時取得 var Date = new Date(); var Hours = Date.getHours();
- 変数
Date
でDate()
インスタンスを生成 - 変数
Hours
でgetHours()
メソッドによってDate
の時間を取得
この部分はJSにあらかじめ用意されている組み込み関数なのでVue.jsではありません。
先ほどのHTMLのv-show
属性の条件で時間が読み込まれていますね。「時間が18以上であれば表示する」という意味になります。
//本文 var app = new Vue({ el: '#app', data: { message: ' びゅう!' } })
続く変数app
のVue
インスタンスはこれまでと同じ構成ですね。
HTMLの{{massage}}
に文字列が表示されます。
v-showの表示はCSSのdisplay
プロパティで切り替えられます。デベロッパーツールなどで見ていただくとspan
要素は0〜17時台まではdisplay: none;
になっていることがわかります。
v-if
次はv-ifディレクティブの事例です。v-ifは条件と合わない場合はdisplay: none;
の表示切り替えではなくオブジェクト自体が生成されません。また、v-showよりもelse
などの複雑な分岐を設定できます。
一見単なるテキストが一行あるように見えます。しかしこのテキストの頭の挨拶部分は見る時間帯によって「おはようございます」「こんにちは」など表示が変わります。
<p id="app"> <span v-if="Hours <= 11">おはようございます</span> <span v-else-if="Hours <= 17">こんにちは</span> <span v-else-if="Hours <= 23">こんばんは</span> <span v-else-if="Hours <= 5">おやすみなさい</span> {{ message }} </p>
- id名
app
のp要素の中にspan要素が4つ入っている。 - 1つ目のspan要素は
v-if
ディレクティブで条件はHours <= 11
- 2つ目のspan要素は
v-else-if
ディレクティブで条件はHours <= 17
- 3つ目のspan要素は
v-else-if
ディレクティブで条件はHours <= 23
- 4つ目のspan要素は
v-else-if
ディレクティブで条件はHours <= 5
- 二重波括弧
{{ }}
でmessage
を読み込む
JSのif文と似ているので想像がつくと思いますがv-else-if
はif文のelse if
と同様「さもなくは、もし」という意味。これ以外に「さもなくば」のelse
と同じv-else
ディレクティブもあります。
条件は上からHours
(時間)が11時台以下(<=
)なら、17時台以下なら、23時台以下なら、5時台以下なら、という意味。
それではJSを見ていきましょう。
//日時取得 var Date = new Date(); var Hours = Date.getHours(); //本文 var app = new Vue({ el: '#app', data: { message: ' びゅう!' } })
先ほどと全く同じですね。上で変数Hours
に時間を取得し、下の変数app
でmessage
に文字列「びゅう!」を代入。
HTMLの書き方を変えるだけで同じJSでも挙動が変わりました。時間によって挨拶がかわるわけです。
デベロッパーツール で見ると、元のHTMLでは4つあったspan要素が時間帯に該当する一つしか描画されていないことがわかります。これがv-show
との違いです。
ループ(v-for)
最後にVue.jsの「ループ」のディレクティブ、v-for
です。
チュートリアルはこちら。
配列数分ループ
なんだか一年中理由をつけて酒を飲んでいるようですね。「日本全国酒飲み音頭」の歌詞です。
※参考:元ネタはこちら
https://youtu.be/I9kBzcfnsyM
コードを見ていきましょう。HTMLはこちら
<h1 id="title">{{ title }}</h1> <ul id="sake"> <li v-for="value in sake"> {{ value }} </li> </ul>
- id名
#title
のh1要素、二重波括弧{{ }}
でtitle
を読み込む。 - id名
#sake
のul要素の中にはli要素が一つだけある。 - li要素には
v-for
ディレクティブがあり、属性値はvalue in sake
。 - 二重波括弧
{{ }}
でvalue
を読み込む。
具体的な文字列が全くなく、li要素も一つだけでかなりシンプルですね。JSはどうなっているんでせう?
var title = new Vue({ el: '#title', data: { title: '日本全国酒飲み音頭' } })
- 変数
titel
でVueインスタンスを生成し el
キーで#title
と紐付けdata
キーに入れ子のtitle
キーで文字列「日本全国酒飲み音頭」読み込み。
前半は見慣れた構成です。#title
のh1要素に曲のタイトルを読み込ませます。後半を見てみましょう。
var sake = new Vue({ el: '#sake', data: { sake: [ "1月は正月で酒が飲めぞ", "2月は豆まきで酒が飲めるぞ", "3月はひな祭りで酒が飲めるぞ", "4月は花見で酒が飲めるぞ", "5月は子供の日で酒が飲めるぞ", "6月は田植えで酒が飲めるぞ", "7月は七夕で酒が飲めるぞ", "8月は暑いから酒が飲めるぞ", "9月は台風で酒が飲めるぞ", "10月は運動会で酒がめるぞ", "11月は何でもないけど酒が飲めるぞ", "12月はドサクサで酒が飲めるぞ", ] } })
- 変数
sake
でVue
インスタンス生成 el
キーで#sake
と紐付けdata
キーに入れ子のsake
キーの値は配列で曲の歌詞が12個入っている。
これで#sake
のul要素内のli要素がv-for
ディレクティブの条件sake
キーの値の数量分ループするわけです。実行されるのはvalue
キーへのsake
キーの値の読み込みです。
ループ回数を読み込む
さて、sake
キーの値を見て見ると酒が飲めるぞ
の部分が重複していて冗長に感じますね。また、「●月は」の部分の月の数値もループの回数を入れられると一致しそうです。こんな感じです。
見た目のアウトプットは全く同じなんですけどね。コードはどのように変わったのでしょうか。
<h1 id="title">{{ title }}</h1> <ul id="sake"> <li v-for="(value, index) in sake"> {{ index +1 }}月は{{ value }}酒が飲めるぞ </li> </ul>
li要素の部分が変わりました。
- li要素の
v-for
ディレクトレィブの属性値が(value, index) in sake"
に。 - 二重波括弧
{{ }}
でindex
を読み込み1
を加算。同じく二重波括弧{{ }}
でvalue
も読み込む。その他の共通部分はそのまま書く。
JSを見てみましょう。
var title = new Vue({ el: '#title', data: { title: '日本全国酒飲み音頭' } })
前半は先ほどと同じですね。曲のタイトル読み込み。後半はこちら。
var sake = new Vue({ el: '#sake', data: { sake: [ "正月で", "豆まきで", "ひな祭りで", "花見で", "子供の日で", "田植えで", "七夕で", "暑いから", "台風で", "運動会で", "何でもないけど", "ドサクサで", ] } })
全体の構造は先ほどと同じなのですがsake
キーの値から重複する文字列が消えてユニークな部分のみになりました。スッキリ!
HTMLのv-for
ディレクティブの第二引数にindex
を加えると、配列のループ回数を読み込むことができます。0からカウントするので1加算します。
これで「1月は」「2月は」とループ回数をカウントアップして読み込むことができるようになりました。
最後に
まずはシンプルなことしかやっていないので、まだ生JSやjQueryでも実現できる範囲です。基本的にはセレクタ名と紐付けるので、DOMの親子関係はそんなに意識しないで済みそうです。書式も配列っぽくてシンプル。
また、「ループ」でやったことが、なんとなく前回の「JSONファイル読み込み」に通じるそうに思えたので、次回ははっぴいえんどのアルバム情報のJSONファイルをVue.jsで読み込めないかトライしたく思います!
※参考:Vue.jsの習得のためにやったことまとめ
qiita.com