Chapter 01

petite-vueをはじめよう

OJK
OJK
2021.08.27に更新

はじめに

本講座では、JavaScript のフレームワークのひとつである petite-vue(プチ・ビュー)を使った簡単なアプリケーション開発について学びます。

ここでいう “フレームワーク/Framework” とは、「こういう記法で書いて、こういうふうに動作させてね」というルールの集まり(枠組み)のことです。プログラミングの文法自体は JavaScript なのですが、その上に petite-vue 独自の記法が加わります。素の JavaScript だけを使って記述すると面倒な処理が簡単に記述できるようになります。

petite-vue を導入すると、マークアップ言語である HTML で変数・関数・制御構文(if 文・for 文)が使えるようになります。プログラミング言語で書けば数行で済みそうなパターン化された記述を HTML で延々と書いた経験があれば、その便利さが想像できるかと思います。もうひとつは、HTML のフォームの値と JavaScript の変数を簡単に紐付けられることです。JavaScript でフォームの値を取得するのは結構面倒でしたよね。あの記述が簡潔になります。

なお、petite-vue は、もう少し本格的なフレームワークである Vue の簡易版です。petite-vue はアプリケーション開発というより、ウェブページをインタラクティブにする用途で使います。本家 Vue のほうはアプリケーションの各パーツをファイルに分けて管理できる(SFC:Single File Component といいます)など、本格的なアプリケーション開発で利用されます。それ以外の基本的なところでは petite-vue と Vue の記法はほぼ同じです。本講座では petite-vue と Vue 異なるところのみ、その都度注釈します。

なお、本講座の執筆時点(2021 年夏)では、JavaScript フレームワークのデファクトスタンダード(事実上の標準)は React です。また、Svelte も Vue を追い上げています(人気だけなら追い越しています)。ただ、React は 学習曲線の最初のカーブが急であり、Svelte は Node.js がないと動かせないため、とにかく初心者にとって敷居の低い petite-vue を本講座では選びました。

React や Svelte をフレームワークとして取り上げましたが、厳密には、React は “ライブラリ” であり、Svelte は “コンパイラ” です。説明すると長くなるので割愛しますが、「フレームワーク=ライブラリ+独自の記法」という認識でよいかと思います。petite-vue/Vue もライブラリとして提供されていますが、独自の記法が比較的多いです。なお、コンパイラのほうはライブラリやフレームワークとは全くの別物です。

なお、本講座は HTML・CSS・JavaScript の基礎をすでに習得済みであることを前提としています。これらの言語をまだ勉強していないという人は次のテキストにまず取り組んでください。

petite-vue をはじめよう

petite-vue を導入する方法はいくつかあるのですが、本講座では混乱しないように以下の書き方で統一します。この導入方法なら適当なエディタとブラウザがあれば動きます。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>petite-vue入門</title>
</head>
<body>

  <p>Hello {{message}}</p>

  <script src="https://unpkg.com/petite-vue"></script>
  <script src="script.js"></script>
</body>
</html>
script.js
'use strict';

PetiteVue.createApp({
  message: 'World!!'
}).mount();

上記の 2 つのファイル(index.html と script.js)を同じフォルダに保存して index.html をブラウザで開いてください。「Hello World!!」と表示されたら成功です。本講座では Visual Studio Code を使用する前提にしていますが、エディタは何でも構いません。ウェブエディタなら実行ボタンのある Replit がお勧めです。

ここでは <p>{{message}}</p> は後回しにして、petite-vue を使うために必要な部分について説明していきます。

まず、次の 1 行で petite-vue の機能が使えるようになります。PetiteVue というオブジェクトが読み込まれます。

index.html側
<script src="https://unpkg.com/petite-vue"></script>

JavaScript 側では、PetiteVue オブジェクトの createApp メソッドを呼び出します。

script.js側
PetiteVue.createApp({
  /* ここに変数(プロパティ)や関数(メソッド)を記述する */
}).mount();

createApp メソッドの引数が「オブジェクト」になっていることに注意してください({ }で囲われている)。この引数(=オブジェクト)のプロパティとして、HTML 側で使用するプロパティ(変数)やメソッド(関数)を定義していきます。本講座では、JavaScript 側(script.js)の記述は、全てこの createApp メソッドの引数の中の話になります。

createApp メソッドの最後の .mount() については後述します。

Vue の場合

本家 Vue は通常 Node.js というツールを使って開発環境を整えるのですが、petite-vue のように script 要素を 1 行記述するだけでも使えます。その場合は以下の 2 点を変更するだけです。

index.html側
<!-- URLをちょっと変更 -->
<script src="https://unpkg.com/vue@next"></script>
script.js側
// PetiteVueをVueに変更
Vue.createApp({}).mount('body');
// mountメソッドの引数が必須

Mustache 構文(口ひげ構文)

最初のサンプルの HTML には次のように書かれていました。ファイルをブラウザで開くと、{{ message }} 部分が「World!!」という文字列に置き換えられたかと思います。

HTML
<p>Hello {{message}}</p>

この message という文字列は、JavaScript 側の createApp メソッドの引数に渡されたオブジェクト内で宣言されたプロパティ message と紐付けられています。このプロパティのことを Vue では データプロパティ と呼び、この紐付けのことを “データバインディング” といいます。

JS
PetiteVue.createApp({
  message: 'World!!'
}).mount();

{{ }} を使ったデータバインディングは Vue の テンプレート構文 と呼ばれる記法のひとつで、“Mustache 構文” といわれるものです。Mustache(マスターチュ)は日本人には馴染みの薄い英単語なので、本講座では「口ひげ構文」と呼ぶことにします。

Vue/petite-vue のデータプロパティはいくつでも宣言できますし、値も文字列に限られません。データプロパティは JavaScript のオブジェクトのプロパティそのものなので、制約も同じです。

HTML
<p>{{message}} {{count}}</p>
JS
PetiteVue.createApp({
  message: 'Count:',
  count: 1
}).mount();
Vue の場合

本家 Vue のデータプロパティの記法は petite-vue とは異なり、data というメソッドの戻り値として記述します。戻り値の中身は JavaScript のオブジェクトなので、データプロパティ自体の記法は petite-vue と同じです。

Vue.createApp({
  data() {
    return {
      message: 'Count:',
      count: 1
    }
  }
}.mount();

口ひげ構文で指定したデータプロパティ名を間違えるなど、一箇所でもミスがあると口ひげ構文は展開されず、{{データプロパティ名}} のまま残ります。ブラウザの開発者モードを開いて常にコンソールを確認しながら作業するようにしてください。

なお、口ひげ構文は HTML の開始タグと終了タグの間でのみ使えます。タグの中で「<img src={{filename}}>」というように書くことはできません。HTML の属性値とのバインディングについてはチャプター 4で説明します。

素の JavaScript と比較する

試しに、上記のサンプルコードと同じことを素の JavaScript で書いてみましょう。いろいろな書き方ができますが、例えば以下のようになるでしょう。

HTML
<p>
  <span id="message"></span><span id="count"></span>
</p>
JS
const message = 'Count:';
let count = 1;
document.getElementById('message').textContent = message;
document.getElementById('count').textContent = count;

いかがでしょう。petite-vue を使うことで少しはシンプルになっているかと思います。

ただ、JavaScript フレームワークが本当に便利になってくるのは、データプロパティを変更したときです。例えば、ボタンを押すたびに HTML の表示を変えるためには、素の JavaScript では次のように記述します。

HTML
<p>
  <span id="message"></span><span id="count"></span>
</p>
<button>増加</button>
JS
const message = 'Count:';
let count = 1;
document.getElementById('message').textContent = message;
document.getElementById('count').textContent = count;

// ボタン要素にクリックイベントの処理を登録
const btn = document.querySelector('button');
btn.addEventListener('click', ()=>{
  count += 1;
  document.getElementById('count').textContent = count;
});

変数 count の値が変わるたびに対応する span 要素の textContent を更新する必要があります。同じコードが 2 箇所に登場していますね。

これを petite-vue で書いてみましょう。クリックイベントの取得についてはまだ解説していませんが、なんとなくわかると思います

HTML
<p>{{message}} {{count}}</p>
<button @click="count += 1">増加</button>
JS
PetiteVue.createApp({
  message: 'Count:',
  count: 1
}).mount();

button 要素に @click = "count += 1" という属性が加わっただけで、JavaScript 側には変化がありません。@click はクリックしたときの処理を指定する Vue の記法で、count += 1 がその処理内容です。ボタンをクリックするとデータプロパティ count が 1 ずつ増えます。

データプロパティが変化すると、対応する口ひげ構文の中身も同期して変化します。このさき学ぶ口ひげ構文以外のデータバインディングでも同じです。このことを「“リアクティブ/Reactive” である」といいます。

petite-vue を一部に適用する

createApp メソッドの末尾の .mount() に引数を与えると、特定の HTML 要素の配下にのみ petite-vue を適用することができます。引数には、petite-vue を適用したい HTML 要素を CSS セレクタの書式で指定します。

PetiteVue.createApp({
  /* ... */
}).mount('CSSセレクタ')

次の例では 2 つの div 要素にそれぞれ createApp メソッドを用意しています。2 つの createApp メソッドの引数内で count という名前の変数を定義していますが、それぞれ個別に扱われていることがわかります。

HTML
<div id="abc">
  <p>ABC Count: {{count}}</p>
</div>

<div id="xyz">
  <p>XYZ Count: {{count}}</p>
</div>
JS
PetiteVue.createApp({
  count: 1
}).mount('#abc');

PetiteVue.createApp({
  count: 2
}).mount('#xyz');

アプリケーションが大きくなってきて、複数の領域で使用する変数や関数に重複のないときは createApp メソッドを分けると管理がしやすいでしょう。

ただし、適用範囲を入れ子の状態にはできないので、選んだタブによって表示する中身を切り替えるような用途には使えません。

HTML
<div id="main">
  <p>Tab: {{tab}}</p>
  <!-- tabの値によって表示するdiv要素を切り替えたい -->
  <div id="abc">
    <p>ABC Count: {{count}}</p>
  </div>
  <div id="xyz">
    <p>XYZ Count: {{count}}</p>
  </div>
</div>
JS
PetiteVue.createApp({
  tab: 'abc'
}).mount('#main');

PetiteVue.createApp({
  count: 1
}).mount('#abc');

PetiteVue.createApp({
  count: 2
}).mount('#xyz');

入れ子になるような用途には別の方法が用意されています。HTML の template 要素を使って HTML も分けて管理することができます。記法がやや複雑になるので、本講座の最後のほうに取り上げたいとと思います。


以上、petite-vue を紹介してきましたが、「こういうふうに書く」というルールが決められていることがわかるかと思います。これがフレームワークと呼ばれる所以です。

口ひげ構文以外にも、HTML 内で使える条件分岐や繰り返しの構文、イベントやフォームとの関連付けなど、petite-vue のテンプレート構文はいくつかあります。本講座はそれらを順番に紹介していく形で進めていきます。

とはいっても、プログラミング言語自体は JavaScript で、createApp メソッドの引数に与えたオブジェクトを設定しているだけです。JavaScript の文法を忘れてしまった…という人はオブジェクト戻り値ありの関数メソッドの定義を復習してから先に進んでください。