株式会社グローバルゲート公式ブログ

Blog

2020-02-04

近年人気のJavascriptフレームワーク「Vue.js」でできるインタラクティブな制作事例

こんにちは。グローバルゲート制作部のモーリーです。

2020年もあっという間に1ヶ月が終わり、2月に入りました。
多くの会社様では年度末に向けて、さらにその先のGWやオリンピック期間に向けて多忙な日が続くかと思いますが、体調にはくれぐれもご留意くださいますようお願い申し上げます。


さて、本日の記事では近年人気のJavascriptフレームワーク「Vue.js」についてご紹介します。




Vue.jsとは

Javascriptのフレームワークで、近年利用事例が急激に増えている人気のフレームワークです。

Vue.js(wikipedia)

当社業務でも一部採用しているのですが、開発者としては実際に使ってみて

・コンポーネント化による管理のしやすさ
・扱うデータがJSONで管理、編集がしやすい
・フルPHPに比べて表示が高速

などのメリットを実感しました。

一般のお客様にとっては、Vue.jsでどんなことができるのか、どんなサイトが作れるのかという点が気になることと思います。
そこで実際に動作する事例を作成しましたので、ぜひご覧ください。

デモ

ちなみに作者の方が好きなのか、コードネームが全部日本のアニメや漫画です。次期バージョンの2.7はNからはじまるアニメか漫画になりますが、何が来るのでしょう?


入力したデータを元に計算し、即時にページに表示する(BMI計算機)

それでは、実際の事例をご紹介します。

一般のサイトでVue.jsを採用する理由の一つとして、入力されたデータと表示を連動させるリアクティブシステムがあります。
簡単に言うと「何かを入力したらその内容を加工して表示させる」なのですが、jQueryなど他のライブラリで同様の操作を行うと

・データの入力があったかどうかを判定する
・入力されたデータを取得する
・取得したデータを表示する
・再入力されたら一旦初期化する

など細かく条件分岐を考えていかないといけません。

Vue.jsならこれらの操作を非常に簡単に実装することができます。

HTMLはVue.js特有の属性や構文がありますが、ほぼ通常のHTMLそのままです。

<div class="row">
                   <div class="col">
                       <div class="form-group">
                           <label for="bmi-height">身長</label>
                           <div class="input-group">
                               <input type="number" class="form-control" id="bmi-height" v-model.number="bmiHeight"
                                   placeholder="170">
                               <div class="input-group-append">
                                   <span class="input-group-text">cm</span>
                               </div>
                           </div>
                       </div>

                   </div>
                   <div class="col">
                       <div class="form-group">
                           <label for="bmi-weight">体重</label>
                           <div class="input-group">
                               <input type="number" class="form-control" id="bmi-weight" v-model.number="bmiWeight"
                                   placeholder="60">
                               <div class="input-group-append">
                                   <span class="input-group-text">kg</span>
                               </div>
                           </div>
                       </div>
                   </div>
                   <div class="col">
                       <p>あなたのBMIは<br><strong class="display-4">{{ bmi }}</strong><br>です。</p>
                   </div>
               </div>

v-modelとなっているところがユーザーの入力を受け付ける部分です。
その内容を元に、BMIを計算して{{ bmi }}というところに表示させます。

Javascript部分はとてもシンプル!
数行でBMIが計算されました。そろそろ春の気配を感じさせる気候になってきましたので、夏に向けて6LDKの腹筋を目指しましょう!

var app = new Vue({
   el: '#app',
   data: {
       bmiHeight: null,
       bmiWeight: null,
   },
   computed: {
       bmi() {
           var bmi = Math.round(this.bmiWeight / Math.pow(this.bmiHeight / 100, 2) * 10) / 10;
           return bmi ? bmi : '';
       }
   }
});

マラソンの完走タイム計算機

まったく同じ要領ですが、入力されたデータの計算式さえ変えれば違う結果を導き出せます。
たとえば以下の例は、ランニングのペース(1kmあたりの時間)を入力したら42.195kmを走るのにどれだけ時間がかかるかを計算します。

<div class="row align-items-center">
                   <div class="col-auto">
                       1kmを
                   </div>
                   <div class="col">
                       <input type="number" class="form-control" id="run-min" v-model.number="runMin" placeholder="5">
                   </div>
                   <div class="col-auto">
                       分
                   </div>
                   <div class="col">
                       <input type="number" class="form-control" id="run-sec" v-model.number="runSec" placeholder="30">
                   </div>
                   <div class="col-auto">
                       秒で走ると
                   </div>

                   <div class="col-12 mt-3">
                       <strong class="display-4">
                           {{ totalTime }}</strong class="display-4">で完走できます。
                   </div>
               </div>

var app = new Vue({
   el: '#app',
   data: {
       runMin: null,
       runSec: null,
   },
   computed: {
       totalTime() {
           var totalSec = (this.runMin * 60 + this.runSec) * 42.195;
           var h = Math.floor(totalSec / 3600);
           var mTemp = totalSec % 3600;
           var m = Math.floor(mTemp / 60);
           var sTemp = mTemp % 60;
           var s = Math.round(sTemp);

           if (h && m && s) {
               return h + '時間' + m + '分' + s + '秒';
           } else {
               return '';
           }
       }
   }
})

ちなみに1kmを4分で走っても(結構速いです)マラソンのタイムは2時間48分47秒と日本代表にもなれないタイムになってしまいます。
日本記録の2時間5分や世界記録の1時間59分(非公認)がどれほど速いかがよく分かります。


現在時刻を取得し、角度に置換して反映(アナログ時計)

これまでは入力されたデータを元に計算を行って出力していましたが、元となるデータは入力されるものとは限りません。
たとえば、現在時刻をベースとすると、アナログ時計をつくることができます。

<div class="row">
                   <div class="col">
                       現在時刻は<br><strong class="display-4">{{ currentTime }}</strong><br>です。
                   </div>
                   <div class="col">
                       <div class="clock">
                           <div class="bar-hour" :style="{transform: 'rotate(' + currentHour * 30 + 'deg)'}"></div>
                           <div class="bar-min" :style="{transform: 'rotate(' + currentMin * 6 + 'deg)'}"></div>
                           <div class="bar-sec" :style="{transform: 'rotate(' + currentSec * 6 + 'deg)'}"></div>
                       </div>
                   </div>
               </div>

var app = new Vue({
   el: '#app',
   data: {
       currentTime: '',
       currentHour: '',
       currentMin: '',
       currentSec: '',
   },
   mounted() {
       var vm = this;
       vm.updateTime();
       setInterval(vm.updateTime, 1000);
   },
   methods: {
       updateTime() {
           var today = new Date();
           this.currentTime = today.getHours() + '時' + today.getMinutes() + '分' + today.getSeconds() + '秒';
           this.currentHour = today.getHours();
           this.currentMin = today.getMinutes();
           this.currentSec = today.getSeconds();
       }
   }
})

setIntervalは一定時間で同じ処理を繰り返す関数です。
ここでは1000ミリ秒(つまり1秒)ごとに針の角度をアップデートしていますので、クオーツ式時計の動きを模しています。
この数値を1秒以下にすると自動巻ムーブメントのような秒針も再現できます。


input[type=”range”]の入力値を元にCSSスタイルを生成(box-shadowのプレビュー)

HTMLでの入力というと、文字を入力するテキストエリアかチェックボックスかラジオボタンでしたが、ブラウザの進化によってスライダーで数値を入力するrangeというスタイルも使えるようになりました。

スライダーを操作することでその入力値(数値になります)がCSSのスタイルに反映されるため、見た目も面白くついつい遊んでしまいたくなる表現も簡単にできます。

<div class="row">
                   <div class="col">
                       <div class="form-group">
                           <label for="box-shadow-x">X方向の距離</label>
                           <div class="row">
                               <div class="col">
                                   <input type="range" id="box-shadow-x" class="form-control" min="-50" max="50"
                                       v-model="shadowX">
                               </div>
                               <div class="col-4">
                                   <div class="input-group">
                                       <input type="text" class="form-control" v-model="shadowX">
                                       <div class="input-group-append">
                                           <span class="input-group-text">px</span>
                                       </div>
                                   </div>
                               </div>
                           </div>
                       </div>
                       <div class="form-group">
                           <label for="box-shadow-y">Y方向の距離</label>
                           <div class="row">
                               <div class="col">
                                   <input type="range" id="box-shadow-y" class="form-control" min="-50" max="50"
                                       v-model="shadowY">
                               </div>
                               <div class="col-4">
                                   <div class="input-group">
                                       <input type="text" class="form-control" v-model="shadowY">
                                       <div class="input-group-append">
                                           <span class="input-group-text">px</span>
                                       </div>
                                   </div>
                               </div>
                           </div>
                       </div>
                       <div class="form-group">
                           <label for="box-shadow-range">ぼかしの距離</label>
                           <div class="row">
                               <div class="col">
                                   <input type="range" min="0" max="50" id="box-shadow-range" class="form-control"
                                       v-model="shadowRange">
                               </div>
                               <div class="col-4">
                                   <div class="input-group">
                                       <input type="text" class="form-control" v-model="shadowRange">
                                       <div class="input-group-append">
                                           <span class="input-group-text">px</span>
                                       </div>
                                   </div>
                               </div>
                           </div>
                       </div>
                       <div class="form-group">
                           <label for="box-shadow-bokeh">広がる距離</label>
                           <div class="row">
                               <div class="col">
                                   <input type="range" min="-50" max="50" id="box-shadow-bokeh" class="form-control"
                                       v-model="shadowBokeh">
                               </div>
                               <div class="col-4">
                                   <div class="input-group">
                                       <input type="text" class="form-control" v-model="shadowBokeh">
                                       <div class="input-group-append">
                                           <span class="input-group-text">px</span>
                                       </div>
                                   </div>
                               </div>
                           </div>
                       </div>
                   </div>
                   <div class="col d-flex justify-content-center align-items-center">
                       <div class="shadowEx border border-dark" :style="{'box-shadow': shadow}">

                       </div>
                   </div>
                   <div class="col-12">
                       <div class="bg-light border p-4">
                           <pre class="mb-0">/* 下記CSSをコピペして使えます。 */
box-shadow: {{ shadow }};</pre>
                       </div>
                   </div>
               </div>

var app = new Vue({
   el: '#app',
   data: {
       shadowX: 0,
       shadowY: 0,
       shadowRange: 0,
       shadowBokeh: 0,

   },
   computed: {

       shadow() {
           return this.shadowX + 'px ' + this.shadowY + 'px ' + this.shadowRange + 'px ' + this.shadowBokeh + 'px #000';
       }
   }
})

ちなみに写真やグラフィックの世界で「焦点が合っていない」「境界が明瞭でない」などのことを「ボケ」と言いますが、英語圏でもBokehといいます。面白いですね。


ひ゛ら゛が゛な゛に゛濁点を゛つ゛け゛る゛っ゛っ゛!

最後に、入力したテキストが藤原竜也になってしまう方法のご紹介です。

<div class="row align-items-center">
                   <div class="col-12">
                       <div class="form-group">
                           <textarea name="tatsuya" class="form-control" v-model="tatsuya"
                               placeholder="キンキンに冷えてやがるっ・・・!!"></textarea>
                       </div>
                   </div>
                   <div class="col-12 text-center py-3">
                       ↓ ↓ ↓
                   </div>
                   <div class="col-12 display-4">
                       <div class="border bg-light p-4">
                           <strong>{{ tatsuya | toTatsuya }}</strong>
                       </div>
                   </div>
               </div>

今回はVue.jsの機能の中でも、入力データを表示時のみ加工するfiltersを使ってみました。
filtersで編集されたデータは再利用ができませんので、実践的には数値にカンマ区切りを入れたり「円」を末尾に追加したり、というような場面で使います。

var app = new Vue({
   el: '#app',
   data: {
       tatsuya: ''
   },
   filters: {
       toTatsuya(val) {
           return val.replace(/([あ-んア-ン])/g, "$1゛");
       }
   }
})

まとめ

今回はエンジニアの間で人気のあるVue.jsの使用例をご紹介しました。
私達グローバルゲートでは新しい技術を取り入れつつ、もちろん古くとも有用な技術も活用しつつ、お客様にとって最適なWebサイトづくりを目指して日々精進しています。

Webサイト制作やその他IT関連のご相談は

お゛気軽に゛お゛問い゛合わ゛せ゛く゛だ゛さ゛い゛!!!!


ご相談・お問い合わせ

当社サービスについてのお問い合わせは下記までご連絡下さい。

お電話でのお問い合わせ

06-6121-7581 / 03-6415-8161