九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、前回 Vue componentで気をつけるべきこと!という記事を投稿しましたけど、この記事を書いている最中にふと思うことがありました。
それが、「そういえばVueのディレクティブ(例:v-if)って全部知ってるんだろうか??」と。
他のJSライブラリでもそうなんですけど、最近はホントに進化が早いんで、後から「え!そんな便利なものがあったのか・・・時間を無駄にしていたよ(汗)」となることも多々あったりするので、そうならないために今回はVueの全ディレクティブを実例でまとめてみたいと思います。
目次
v-on
イベントを指定するディレクティブですね。jQueryでいうところの「on(‘****’)」。
使い方は、以下のようになります。
<button type="button" v-on:click="onClick()">ボタン</button>
そして、呼び出される側はmethodsの中に書きます。
new Vue({ el: '#app', methods: { onClick: function() { alert('クリックされました!'); } } });
ただ、実際に私がよく使うのは「v-on:*****」の方ではなく、省略形の「@*****」です。同じ動きならできるだけコードは少ないほうが可読性が上がるので。
<button type="button" @click="onClick()">ボタン</button>
また、もちろんボタンだけじゃなくリンクや入力ボックスにもイベントを設定することもできます。
<a href="#" @click.prevent="onClick()">リンク</a>
※リンクの場合は、クリックするとイベント実行時にアドレスが「#」に移動してしまうので、「prevent」を使ってアドレスの変更を阻止しています。
<input type="text" @keyup.enter="onKeyupEnter()">
※この例はエンターキーを押したときにイベント実行される例です。
この他にも色々なイベント拡張機能があるので、興味がある場合はこちらをご覧ください。
v-for
たくさんのデータをループさせる命令文です。いわゆる「forループ」ですね。
例えば、以下のような名前データを持った配列をループさせて表示してみましょう。
new Vue({ el: '#app', data: { names: [ '桃太郎', '金太郎', 'かぐや姫', '浦島太郎', '一寸法師' ] } });
v-forの中に「in」を使って各データを格納する記述をします。(Pythonと似てますね。)
<div v-for="name in names">{{ name }}</div>
(実行結果)
ちなみに「v-for」には色々な追加機能が備わっていて、配列のインデックスやオブジェクトのキーを取得するのも簡単です。
例えば、さっきの例を使うとこうなります。
<div v-for="(name,id) in names">{{ name }}(Index: {{ id }})</div>
(実行結果)
では、データが「キー」を持つオブジェクトの場合も見てみましょう。
new Vue({ el: '#app', data: { names: { momo: '桃太郎', kin: '金太郎', kaguya: 'かぐや姫', ura: '浦島太郎', issun: '一寸法師' } } });
<div v-for="(name,key) in names">{{ name }}(キー: {{ key }})</div>
(実行結果)
ちなみに、オブジェクトだけどインデックスも取得したい場合はどうすればいいでしょうか。以下のようにインデックス変数を3つ目に追加するだけでOKです。
<div v-for="(name,key,id) in names">{{ name }}(インデックス: {{ id }})(キー: {{ key }})</div>
(実行結果)
※ちなみにv-forを使うときに気をつけておくべきことも記事で公開しているのでぜひご覧ください。
v-bind
Vueを使う上で最も便利な機能「バインディング」を設定する命令文です。
例はこんなカンジです。
まずはデータに「url」を追加して、
new Vue({ el: '#app', data: { url: 'http://yahoo.co.jp' } });
以下のようにリンクにバインディングしてみましょう。
<a v-bind:href="url">リンク</a>
これを実行すると、データで指定したURLがリンクの「href」に入ってきます。
<a href="http://yahoo.co.jp">リンク</a>
もちろん、以下のように「url」の中身が変更になると、自動的にリンクの「href」が変更されます。
new Vue({ el: '#app', data: { url: 'http://yahoo.co.jp' }, mounted: function() { this.url = 'http://google.com'; } });
(自動的に変更になる)
<a href="http://google.com">リンク</a>
ちなみに、「v-bind」にも「v-on」と同じく省略形があります。
書き方はこんなカンジです。「v-bind」の部分をごっそりなくしてしまってもいいんです。
(省略しない形)
<a v-bind:href="url">リンク</a>
↓↓↓省略形
<a :href="url">リンク</a>
とてもスッキリしたコードになりますね。
次に、スタイルシート(CSS)をバインディングする方法も見ていきましょう。
やり方は色々とありますけど、ここでは「computed」を使う方法を紹介します。
例えば、以下のようにcssを返すcomputedを作っておいて、
new Vue({ el: '#app', computed: { css: function() { return 'text-bold'; } } });
以下のようにバインディングすると、どうなるでしょうか。
<div :class="css">テキスト</div>
結果はこうなります。
<div class="text-bold">テキスト</div>
また、CSSをある条件で切り替えたい場合は、オブジェクトを使えば簡単にできます。
new Vue({ el: '#app', computed: { css: function() { return { 'switch-css': true }; } } });
上の例では、「switch-css」が有効になっているので、実行結果は、
<div class="switch-css">テキスト</div>
となりますが、もし「switch-css」が「false」だった場合は、
<div>テキスト</div>
となります。
※ちなみに「v-bind:style」の場合も同様にできます。ぜひ活用してみてください。
v-model
インプットデータをバインディングするディレクティブです。これを使えば、入力ボックスのデータに変更があったらリアルタイムでVue内のデータも書き換わることになります。
例を見てみましょう。まずは、データに「name」を追加しておきます。
new Vue({ el: '#app', data: { name: '桃太郎' } });
で、inputタグに「v-model」を設定しましょう。
<input type="text" v-model="name">
こうするだけで、
- 入力ボックスの中身が変更されたら、リアルタイムで「name」の値が変わる
- 「name」の値が変更されたらリアルタイムで入力ボックスの中身も変わる
という2つのバインディングを実現することができるようになります。
もちろん、利用できるのはinputタグだけじゃなく、textareaやselectタグでもOKです。
さらに、リアルタイムにデータの書き換えが可能なので選択されている状況に応じてコンテンツを変化させることもできます。
例えば、selectタグを使った以下のような場合です。
<select> <option></option> <option v-for="(name,key) in names" :value="key" v-text="name"></option> </select>
Vue本体はこんなカンジ。
new Vue({ el: '#app', data: { names: { momo: '桃太郎', kin: '金太郎', kaguya: 'かぐや姫', ura: '浦島太郎', issun: '一寸法師' } } });
これを実行すると、名前を選択できるセレクトボックスが表示されることになります。
では、このコンテンツに「もし『桃太郎』が選ばれたら、『どんぶらこ〜』と表示」するにはどうすればいいでしょうか。これも「v-model」を使えば簡単です。
<select v-model="nameKey"> <option></option> <option v-for="(name,key) in names" :value="key" v-html="name"></option> </select> <div v-if="nameKey=='momo'">どんぶらこ〜</div>
さっきのコードに、「v-model」と対応する変数名、そして条件分岐の「v-if」が入ったdivタグを追加します。
そして、v-modelで指定した「nameKey」を変数として宣言します。
new Vue({ el: '#app', data: { names: { momo: '桃太郎', kin: '金太郎', kaguya: 'かぐや姫', ura: '浦島太郎', issun: '一寸法師' }, nameKey: '' } });
たったこれだけでOK。
実行してみると、桃太郎を選んだときだけテキストを表示させることができます。
こんなカンジでv-modelを使うと、セクション分けしてコンテンツを高速に切り替えることができます。
v-if/v-else-if/v-else
「v-if」は条件分岐で表示する/しないを決めるディレクティブです。
「if文」は、ほぼどんなプログラミング言語にもあると思うので、直感的にわかるかと思います。
例えば、テストの点数を変数に入れたコードで実際に試してみましょう。
new Vue({ el: '#app', data: { score: 100 // テストの点数 } });
もし、この状態で以下のような「v-if」を含んだHTMLタグを追加すると、中身の条件が正しくなるので、「100点満点!」が表示されることになります。
<div v-if="score==100">100点満点!</div>
では、点数を80点にしてみると・・・??条件式が正しくなくなってしまうので、今度は何も表示されません。
new Vue({ el: '#app', data: { score: 80 // テストの点数 } });
では、80点の場合も表示したい場合はどうすればいいでしょうか。以下のように「v-else-if」が使えます。
<div v-if="score==100">100点満点!</div> <div v-else-if="score==80">80点。おめでとう!</div>
もしくは、80点「以上」で分岐したい場合は、こんなカンジで条件式を変更すればOK。
<div v-if="score==100">100点満点!</div> <div v-else-if="score>=80">80点以上。おめでとう!</div>
さらに、それ以外の「v-else」を追加すればどんな点数でもテキストを表示することができるようになります。(※「v-else」に条件式は必要ありません)
<div v-if="score==100">100点満点!</div> <div v-else-if="score>=80">80点以上。おめでとう!</div> <div v-else>うーん、、、</div>
v-show
ほとんど「v-if」と同じですけど、表示の仕方が違います。
「v-if」は条件が正しくなった時点で、新しく要素を作るのに対して、「v-show」の場合は、単純にCSSで「表示/非表示」を切り替えているだけです。
例えば、以下の例を見てみましょう。
<div v-if="false">v-ifです。</div> <div v-show="false">v-showです。</div>
これを実行すると両方ともテキストは表示されません。ただし、デベロッパーツールで中身を見てみるとこうなっています。
<div id="app"> <div style="display: none;">v-showです。</div> </div>
「v-show」の方はCSSで表示が消されているのに対して、「v-if」は要素そのものが存在していません。つまり、もし後で条件式が正しくなったら、その時に要素を追加するということになるわけですね。(nullと空白の関係に似てるかもしれません)
v-text/v-html
どちらもHTMLタグ内のテキストを指定するディレクティブです。例を見てみましょう。まずVue本体。nameがあるだけのシンプルな構造です。
new Vue({ el: '#app', data: { name: '桃太郎' } });
ではHTMLタグの方です。
<div v-text="name"></div> <div v-html="name"></div>
ご想像どおり、2つとも「桃太郎」と表示されることになります。
では、次の場合はどうでしょうか。
new Vue({ el: '#app', data: { name: '桃太郎<br>金太郎' } });
前と違うのは、表示させたいテキスト内にHTMLタグを入れてあるという部分です。
実際の表示を見てみましょう。
そうです。「v-text」の場合はテキストとして表示するだけなので、タグもそのまま表示されてしまうことになります。それに対し、「v-html」はキチンとHTMLまで解釈してテキストを表示することが可能です。
ちなみに、二重括弧でも同じようにテキストを表示させることができます。
<div>{{ name }}</div>
ただ、これはVueとは関係ないのですが、Laravelのテンプレート内で使おうとすると同じく二重括弧はPHPコードと解釈されるため、アットマークをつけて表示させなければいけません。
<div>@{{ name }}</div>
このため、私の環境の場合ではより可読性が高い「v-text」を優先的に使っています。
v-pre
中身をそのまま表示するディレクティブです。
例えば、
<span v-pre>{{ ←←← 二重括弧も表示 →→→ }}</span>
とすると、Vueのコードとは解釈されず、そのままの形でテキストが表示されます。
v-cloak
Vueのコンテンツ描画が準備完了するまで、HTMLタグにとどまってくれるディレクティブです。
これを使うと「ページ表示した瞬間にチラッと見えてしまう、二重括弧を表示しない」ようにできます。
例えば、スタイルシートに以下のように「v-cloak」が表示されない設定をしておきます。
<style> [v-cloak] { display: none; } </style>
そして、「v-cloak」と二重括弧のバインディングが入ったdivタグを追加する。
<div v-cloak>{{ name }}</div>
こうすることで、
- ページ表示時はv-cloakがあるので、「display:none」が有効(つまり、表示されない)
- そして、準備が完了したら「v-cloak」がなくなるのでCSSの適用がなくなり表示される
という流れになります。
v-once
v-onceは、一回だけ表示できるディレクティブです。
つまり、後で変数の中身が変更になっても最初のまま、ということになります。
例を見てみましょう。
new Vue({ el: '#app', data: { name: '桃太郎' } });
Vue本体は、データに「name」が入っただけのシンプルなものです。
<div v-once>{{ name }}</div> <button type="button" @click="name='金太郎'">名前を変更</button>
そして、HTMLコード。
1行目は「v-once」が入ったタグ。そして、2行目は「クリックしたら、nameの中身を金太郎に変更する」というものです。
実際の表示はこう。
通常なら、ボタンをクリックすればバインディングが効いているので「桃太郎」は「金太郎」に変更されるはずですが、今回は「v-once」ディレクティブが入っているので、何も変更されることはありません。
独自のディレクティブをつくる
色々とディレクティブを見てきましたけど、実はVueは自分で独自のディレクティブをつくることもできます。(こういうフレキシブルなところが嬉しいですよね。)
では、これも例で見てみましょう。
例えば、「赤いテキストにするディレクティブ」を作る場合です。
Vue.directive('red', { bind: function (el) { el.style.color = 'red'; } });
Vue.directive に独自の名前「red」を指定し、最初に呼ばれたときだけスタイルシートで赤色を適用させています。
使い方は、他のディレクティブと同様、「v-」をつけて使ってください。
<div v-red>赤文字</div>
これを応用すれば、以下のようにいくつものディレクティブを重ねて使うこともできます。
Vue.directive('red', { bind: function (el) { el.style.color = 'red'; } }); Vue.directive('bold', { bind: function (el) { el.style.fontWeight = 'bold'; } });
<div v-red v-bold>赤文字で、太文字</div>
おわりに
ということで、今回はVueのディレクティブをまとめてみました。
昔は、家庭にあるIT機器がそこまでパワフルではなかったので、あまりJavaScriptだけで条件分岐などをするべきではありませんでしたけど、今のマシーンは格安のスマホでさえ一昔前のパソコンよりはるかに高性能なものばかりになってきました。なので、「できるだけJavaScriptを使って各マシーンで計算をしてもらう」というのが、時代の流れなのかなー、と思っています。
ぜひ開発にVueを活用してみてはいかがでしょうか。
ではでは〜。