こんにちは。アイレットデザイン事業部のマークアップ/フロントエンドエンジニアの工藤です。アイレットデザイン事業部ではINSIDE UI/UXと題して、所属デザイナーとエンジニアがデザイン・SEO・アクセシビリティ・UI/UXなどそれぞれスペシャリティのある領域に対する知見を幅広く発信しています。
今回から3回にわたってVue.js再入門シリーズを更新していきます。

Vue.jsの特徴

Vue.jsの大きな特徴に、仮想DOMを使用してビューをレンダリングできることが挙げられます。仮想DOMは、変更があった場合に全体を再描画するのではなく、必要な部分だけを更新することでパフォーマンスを向上できます。

またVue.jsはリアクティブなデータバインディングを特徴としています。
リアクティブなデータバインディングとは、データが変更されると自動的にビューを更新する機能を指します。

これに対して、JavaScriptやjQueryでは直接DOMを操作する必要があります。また、データの変更に対しては基本的にはページの全体を更新する必要があります。

学習のモチベーション

筆者は長くjQueryのレガシーな実装に親しんできたので上記の違いに戸惑うことがあり、改めてVue.jsの学習をしていくことにしました。

Vue.jsのディレクティブについて

Vue.jsは、HTML要素に対して動的な振る舞いを付加できる、ディレクティブと呼ばれる機能を提供しています。ディレクティブはv-で始まる属性によって表され、ビューのレンダリング中にVue.jsが監視し、リアクティブなレンダリングを可能にします。

基本構文

Vue.jsには以下のような基本的なディレクティブがあります。

  • v-if: 真偽に応じて要素を表示または非表示にする。
  • v-show: 真偽に応じて要素を表示または非表示にする。v-ifとは異なり要素がDOMに残るため、頻繁に表示/非表示を切り替えるコンテンツの描画に有効。
  • v-for: 配列やオブジェクトの要素をループして、要素を生成。
  • v-bind: 要素の属性に値をバインドする。省略記法がある。
  • v-bind:style: 要素のスタイルをバインドする。

  • v-bind:class: 要素のクラス属性をバインドする。

  • v-model: フォームの入力値を双方向バインドする。

  • v-on: イベントリスナーをバインドします。省略形として@が利用できる。
  • v-once: 一度だけレンダリングされ、その後は更新されない。

省略構文

v-bindv-onには省略構文があります。以下のように使用します。

<!-- v-bindの基本構文 -->
<a v-bind:href="url">Link</a>

<!-- v-bindの省略構文 -->
<a :href="url">Link</a>

<!-- v-onの基本構文 -->
<button v-on:click="handleClick">Click me</button>

<!-- v-onの省略構文 -->
<button @click="handleClick">Click me</button>

イベントに関わるディレクティブ

Vue.jsに限らずJavaScriptでは「ボタンをクリックした」、「値を入力した」といったイベントをきっかけ(トリガー)に特定のコードが実行されます。イベントをきっかけに動くコードのことをイベントハンドラーと言います。

以下はVue.jsで書いたイベントとイベントハンドラーのコードです。

<div id="app">
<button type="button" @click="onClick">Click Me</button>
<p>{{ message }}</p>
</div>
Vue.createApp({
data() {
return {
message: ""
};
},
methods: {
onClick() {
this.message = new Date().toLocaleString();
}
}
}).mount("#app");

上記のコードではボタンクリックによってHTMLの {{ message }} 部分が、現在時刻に置き換わります。

v-modelと双方向バインディング

v-modelはディレクティブの仲間ですが、テキストボックスやラジオボタン、チェックボックスなどのフォーム要素に使用し、Vue.jsの特徴である双方向データバインディングを実現するのに欠かせない点でより重要であり、使いこなせるようになるととても便利です。

以下の例は、v-model="message"がテキストボックスとmessageデータをバインドし、テキストボックスの値が変更されると、messageデータも同時に更新される実装です。

<div id="app">
<input type="text" v-model="message">
<p>{{ message }}</p>
</div>
Vue.createApp({
data() {
return {
message: ''
}
}
}).mount("#app");

v-modelはv-bindとv-onの組み合わせ

実はv-modelの挙動はv-bindとv-onの組み合わせと言えるため、上記のコードはv-bindとv-onの組み合わせによって書き直すことができます。
実際には簡潔に書けるものをわざわざ冗長に書くシーンは少ないと思いますが、概念の理解に役に立ちますね。

<div id="app">
<input type="text" :value="message" @input="updateMessage">
<p>{{ message }}</p>
</div>
Vue.createApp({
data() {
return {
message: ""
};
},
methods: {
updateMessage(event) {
this.message = event.target.value;
}
}
}).mount("#app");

自分でディレクティブを定義するdirectiveメソッド

Vue.jsでは、自分でカスタムディレクティブを定義することもできます。

以下はmy-directiveという名前のディレクティブを定義しています。少しややこしいですが5つのフック関数(bindinsertedupdatecomponentUpdatedunbind)を持ち、それぞれが特定のタイミングで呼び出される実装です。

Vue.directive('my-directive', {
bind: function (el, binding) {
// bind時の処理を記述
},
inserted: function (el, binding) {
// insert時の処理を記述
},
update: function (el, binding) {
// update時の処理を記述
},
componentUpdated: function (el, binding) {
// componentUpdate時の処理を記述
},
unbind: function (el, binding) {
// unbind時の処理を記述
}
})

上記に対し、HTMLファイルに下記のようにディレクティブを使用すると、自分で定義したフック関数が呼び出されますね。

<div v-my-directive></div>

まとめ

というわけでいったんまとめです!今回学んだディレクティブを使うことで、簡単にDOM要素の表示/非表示、データの双方向バインディング、イベントのハンドリングなど基本的な機能を実現できるようになったはずです(汗)。

この学習を通じて、Vue.jsの特徴や機能について深く理解し、これまで以上に品質の高いwebフロントエンド開発ができるようになりたいと思います。

参考資料

Vue.js 公式ドキュメント
山田 祥寛 『これからはじめるvue.js実践入門』
mio『基礎から学ぶ Vue.js』
【Vue.js2&Vue.js3対応】基礎から【Vuetify】を使った応用まで! 超初心者から最短距離でレベルアップ