Help us understand the problem. What is going on with this article?

Vue Web App Tutorial

11月16日 Web Application 製作入門

富山IT勉強会#4 のハンズオン資料をまとめたものです。
非エンジニア、およびWebアプリ未経験者を対象に簡単なWebアプリ(SPA)を作成するハンズオンを行います。

このハンズオンのゴール(目的)

  • 必要最低限の知識で Webアプリを作れるようになる(概念、環境構築 ~ Local環境での動作確認)
  • 今後、更にレベルアップしていく際の切り口を共有する

おことわり

一日(4h ほど)で行う予定であるため、最低限知っていれば取りあえずアプリが作れる程度に厳選しております。
そのため、かなり内容は端折っておりますのでご了承ください。
また、私自身プログラミング経験はWindowsアプリケーションがほとんどで、
Web関係は直近一年弱程度ですので情報にはかなり偏りがあります。
また、誤情報等、お気付きの場合にはご指摘頂けると幸いです。

やること

  • JavaScript入門(環境構築〜変数、制御構文、クラス、関数を最小限、簡単に。npmコマンドにもふれる)
  • Node.js、Vue を使用したWebアプリケーションを作成(Vue基本構文, Vue/Cliコマンド)
  • expressを使用したWebAPIの作成とWebアプリとの通信(express 最小構成でのWebAPIサーバー構築)
  • 時間があった時のオプション
    • PythonでもWebAPIを作成してみる(Flask 最小構成)
      • -> AI 機能を組み込んだWebAPIへ応用可?
    • Electronを使用したデスクトップアプリ化(electron-vueを使用)
      • -> Web技術を使用したデスクトップアプリ開発へ繋げたい場合
    • CSSフレームワークを使用してみる(vuetify)
      • -> もっと見た目をきれいに、機能的にしたい場合

やらないこと

  • formタグを使ったGet、Post等の通信
  • yarn
  • 本番環境へのデプロイ(ローカル環境でのみの作業とします)
  • セキュリティ関連
  • DataBase操作

1. Web(Server - Client 型アプリケーション) の仕組み

本当にザックリですが図を作ってみました。

image.png

Webサイト、Webアプリなどは、このClient-Server型のアプリケーションになります。
Client Side はChrome等のブラウザを通してサーバーへリクエストを行います。
サーバーPCの中では、この時Apache等のサーバーアプリやデータベースが起動していて、
リクエストに応じた処理を行い、結果をHtmlファイルやJson等で返信します(レスポンス)。

今回は、この図でいうバックエンドのサーバーアプリ部分をexpressで作ります。
また、レスポンスとして返すHtmlファイルを、Vueを使って作成します。

2. 環境構築

Node.jsのインストール

nodejs.org :https://nodejs.org/ja/からLTS版をダウンロード。
ダウンロードされたインストーラーを実行してインストールを行ってください。

Node_js.png

インストール完了後、以下のコマンドをshellへ入力して、バージョンが返ってきたらOK。

node -v
npm -v

visual studio code (vscode) のインストール

vscodeを用いてハンズオンを行いますが、お気に入りのエディタがある場合はそちらを使っていただいてもかまいません。

https://code.visualstudio.com/download から自分のOSに合わせたインストーラーをダウンロードし、インストールを行ってください。

3. JavaScript(というかNode.js)入門

まずはhello world

hello.js
const msg = 'hello world';
console.log(msg);
node ./hello.js

=> hello world

変数の型(es6)

今回使用するもののみピックアップ。

Number

数値型。C#やPython等では整数型(Int)、浮動小数点型(Float)等あったがjsはこれだけ

const pi = 3.14;
var index = 1;

String

文字列型

const message = 'hello world'; // '' で囲む
var name = "huga";             // "" もOK

Boolean

true or false

const flg = true;
console.log(flg);       // => true
console.log(!flg);      // => false

if(flg) {
    console.log('flg is true'); // => flg is true
}

Array(配列)

配列。どちらかというとリストに近いような...

// 宣言方法
const arr = [];                   // arr => [](空配列)
let values = new Array();         // values => [](空配列)

const arr2 = [1,2,3];             // arr2 => [1,2,3]
const values2 = new Array(5);     // values => [ <5 empty items> ] (5要素の配列)
console.log(values2[1]);          // => undefined

// 要素の追加
arr.push(1);
arr.push(2);
console.log(arr);                 // => [1,2]

// 要素の参照
console.log(arr[0]);              // => 1
console.log(arr[1]);              // => 2

// 要素の取り出し
console.log(arr.pop());           // => 2
console.log(arr);                 // => [1]

Function

関数

// 通常?の宣言
function twice(num) {
    return num * 2;
}

// ラムダ式
const joinStr = (str1, str2) => { return str1 + str2; };

console.log(twice(2));                      // 4
console.log(joinStr("hello ", "world"));    // hello world

Object

オブジェクト、連想配列。classとかもes5ではオブジェクトになる?? keyに対して任意のデータを割り当てる

// 宣言
const obj = {};
const obj2 = new Object();

// 要素の追加
obj["id"] = 1;
obj.name = "huga";
obj.getName = function() {
    return this.name;
};
console.log(obj);               // => { id: 1, name: 'huga', getName: [Function] }

// 要素の参照
console.log(obj["id"]);         // => 1
console.log(obj.name);          // => huga
console.log(obj.getName());     // => huga

null, undefined

null は他の言語と大体同じ?参照先が未割当の状態。
undefined はそもそも項目すらない状態?(よくわかってません)
今回はここを理解していなくてもできるようにやっていきます。

const, let, var

var
変数を宣言し、ある値に初期化することもできる。グローバル変数として定義される

let
ブロックスコープのローカル変数を宣言し、ある値に初期化することもできる。
ローカル変数(スコープ内で有効な変数)で、再代入が可能。

const
読み取り専用の名前付き定数を宣言する。
ローカル変数(スコープ内で有効な変数)で、再代入が不可能。

制御構文

if

分岐処理

let flg = false;

if (flg) {
    // 実行されない
}
else {
    // 実行される
}

if (flg != true) {
    // 実行される
}

for

繰り返し処理

const numbers = [1,2,3,4,5];

for (let i = 0; i < numbers.length; i++) {
    const element = numbers[i];
    console.log(element);
    // => 1
    // => 2
    // => 3
    // => 4
    // => 5
}

他にもswich, while 等あります。

参考リンク
- 文法とデータ型(MDN)
- ES2015(ES6) 入門

4. HTML

適当なフォルダをvscodeで開いて、適当な名前.htmlというファイルを作成します。
ファイル内で html と入力すると以下のように補完が表示されると思いますので、html5を選択します。

以下のようにテンプレートが挿入されます。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

</body>
</html>

body タグの中にHTMLを記述していきます。

Header

見出しです。h1 ~ h6まであり、数字が小さい程基本的には表示が大きくなります。
bodyタグの中に記述して確認してみます。

<body>
    <h1>h1 ヘッダーです</h1>
    <h2>h2 ヘッダーです</h2>
    <h3>h3 ヘッダーです</h3>
    <h4>h4 ヘッダーです</h4>
    <h5>h5 ヘッダーです</h5>
    <h6>h6 ヘッダーです</h6>
</body>

〇結果

h1 ヘッダーです

h2 ヘッダーです

h3 ヘッダーです

h4 ヘッダーです

h5 ヘッダーです
h6 ヘッダーです

リスト

リストを表示します。番号付き(<ol></ol>)と番号無し(<ul></ul>)があります。

<body>
    <!-- 番号付きリスト -->
    <ol>
        <li>リスト1</li>
        <li>リスト2</li>
        <li>リスト3</li>
        <li>リスト4</li>
    </ol>

    <!-- 番号無しリスト -->
    <ul>
        <li>リスト1</li>
        <li>リスト2</li>
        <li>リスト3</li>
        <li>リスト4</li>
    </ul>
</body>

〇 結果

  1. リスト1
  2. リスト2
  3. リスト3
  4. リスト4
  • リスト1
  • リスト2
  • リスト3
  • リスト4

表を表示します。

<body>
    <table border="1">
        <tr><th>項目1</th><td>A</td></tr>
        <tr><th>項目2</th><td>B</td></tr>
        <tr><th>項目3</th><td>C</td></tr>
    </table>

    <hr>

    <table border="1">
        <thead>
            <tr><th>キー</th><th></th></tr>
        </thead>
        <tbody>
            <tr><td>項目1</td><td>A</td></tr>
            <tr><td>項目2</td><td>B</td></tr>
            <tr><td>項目3</td><td>C</td></tr>
        </tbody>
    </table>
</body>

〇 結果

項目1 A
項目2 B
項目3 C

キー
項目1 A
項目2 B
項目3 C

入力要素

テキストボックスやボタン、スライダー等。
通常は<form></form>タグの中で使用してGETやPOSTメソッドで送信に使いますが、
Vue等のフレームワークでは変数の操作に用いたりします。

<body>
    <div>
        <h3> テキストボックス </h3>
        <input type="text">
    </div>

    <div>
        <h3> テキストボックス(パスワード) </h3>
        <input type="password">
    </div>

    <div>
        <h3> ボタン </h3>
        <input type="button" value="ボタンです">
    </div>

    <div>
        <h3> チェックボックス </h3>
        チェックしてください<input type="checkbox">
    </div>

    <div>
        <h3> ラジオボックス </h3>
        <input type="radio" name="my-radio" value="radio-item1">ラジオ1
        <input type="radio" name="my-radio" value="radio-item2">ラジオ2
        <input type="radio" name="my-radio" value="radio-item3">ラジオ3
    </div>

    <div>
        <h3> コンボボックス </h3>
        <select>
            <option selected="0">選択アイテム1</option>
            <option>選択アイテム2</option>
            <option>選択アイテム3</option>
            <option>選択アイテム4</option>
        </select>
    </div>

    <div>
        <h3>スライダー</h3>
        <input type="range">
    </div>

    <div>
        <h3> カラーピッカー </h3>
        <input type="color">
    </div>

    <div>
        <h3> FILE API </h3>
        <input type="file" id="file-handler">
    </div>

</body>

〇結果 (Chrome)

image.png

4. Vue入門

準備

Webアプリケーション フレームワークのVueを使用して作成していきます。

〇 参考リンク:
- Vue.js(本家)
- 基礎から学ぶ Vue.js(猫本サイト)

まずはHTMLファイルとスタンドアロン版のVue.js(CDN)を使用してVueの基本構文を確認します。
フォルダ内にvue-starter.htmlを作成し、以下のように入力します。

vue-starter.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Vue Starter</title>
    </head>
    <body>
        <div id="app">
            <!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) -->
        </div>

        <!-- vue.js を読み込んでからVueオブジェクトを記載していく -->
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
            // Vue オブジェクト
            var app = new Vue({
                el: '#app',
                data() {
                    return {
                        // object 形式でプロパティを記述していく
                    };
                },
                // 算出プロパティ(キャッシュされる)
                computed: {

                },
                // 監視プロパティ
                watch: {

                },
                // 関数(キャッシュされない、都度評価される)
                methods: {

                },

                // ライフサイクルフック ---------------------------------------------------
                // https://jp.vuejs.org/v2/api/#beforeUpdate
                beforeCreate() {

                },
                created() {

                },
                mounted() {

                },
                beforeUpdate() {

                },
                updated() {

                },
                activated() {

                },
                deactivated() {

                },
                beforeDestroy() {

                },
                destroyed() {

                }
                // ライフサイクルフック ---------------------------------------------------
            });
        </script>
    </body>
</html>
プロパティ名 説明
el VueでレンダリングするHTML DOMのidを記述する。
data レンダリングで参照されるプロパティ。画面描画のもとになる
computed dataを元に算出されるプロパティ。いわゆるgetter
watch 登録されているdataの変化を監視し、変更があった場合の処理を記述する
methods 関数。ボタンのクリックイベント等、特定のイベントにフックして実行する処理を記述する

ライフサイクルフック

Vueが描画を行う際の特定のタイミングで呼ばれるイベント。
詳しくは以下参照。

宣言的レンダリング(プロパティの参照)

描画DOMエリアとVueオブジェクトを以下のように修正します。

<div id="app">
    <!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) -->
    <p>{{message}}</p>
</div>
// Vue オブジェクト
var app = new Vue({
    el: '#app',
    data() {
        return {
            // object 形式でプロパティを記述していく
            message: 'Hello Vue!'
        };
    }
});

〇結果

image.png

繰り返しレンダリング(v-for)

配列やオブジェクトの要素を繰り返しレンダリングします。
描画DOMエリアとVueオブジェクトを以下のように修正します。

<div id="app">
    <!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) -->
    <p>Array のレンダリング</p>
    <ul>
        <li v-for="(item, index) in itemList">{{index}}: {{item}}</li>
    </ul>

    <p>Object のレンダリング</p>
    <table border="1">
        <thead>
            <th>key</th><th>value</th>
        </thead>
        <tbody>
            <tr v-for="(item, key) in obj"><td>{{key}}</td><td>{{item}}</td></tr>
        </tbody>
    </table>
</div>
data() {
    return {
        // object 形式でプロパティを記述していく
        itemList: [
        'huga',
        'hoge',
        'poyo'
        ],
        obj: {
            name: 'Vue',
            id: 1,
            lang: 'JavaScript'
        }
    };
},

〇結果
image.png

イベント(v-on)

ボタンクリック等のイベントをフックして処理を実行します。
描画DOMエリアとVueオブジェクトを以下のように修正します。

<div id="app">
    <!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) -->
    <button v-on:click="call()">click me!!</button>
</div>
methods: {
    call() {
        alert('button clicked');
    }
},

〇結果
ボタンをクリックするとアラートが表示されます。
image.png

条件付きレンダリング(v-if, v-show)

v-ifv-show共に条件を満たす場合にのみレンダリングされます。
違いは、レンダリングされない場合、以下の点が異なる。
- v-if: レンダリングされない場合、DOMが生成されない。
- v-show: レンダリングされない場合もDOMが生成される。style属性がdisplay: none;となることで表示されなくなる。

描画DOMエリアとVueオブジェクトを以下のように修正します。

<div id="app">
    <!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) -->
    <button @click="toggleFlg()">フラグ切り替え</button>
    <p v-if="isShow == true">フラグがtrue なら描画されます</p>
</div>
data() {
    return {
        // object 形式でプロパティを記述していく
        isShow: true
    };
},
// 関数(キャッシュされない、都度評価される)
methods: {
    toggleFlg() {
        this.isShow = !this.isShow;
    }
}

○結果
ボタンを押すたびに下部のテキストの表示、非表示が切り替わります。

算出プロパティと監視プロパティ(computed,watch)

描画DOMエリアとVueオブジェクトを以下のように修正します。

<div id="app">
    <!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) -->
    <h2>computed</h2>
    <p>num is: {{num}}</p>
    <p>twice is: {{twice}}</p>
    <button @click="increment()">numへ1加算</button>

    <h2>watch</h2>
    <p>{{watchStr}}</p>
</div>
data() {
    return {
        // object 形式でプロパティを記述していく
        num: 1,
        watchStr: ""
    };
},
// 算出プロパティ(キャッシュされる)
computed: {
    twice() {
        // 二乗の数を返す
        return Math.pow(this.num, 2);
    }
},
// 関数(キャッシュされない、都度評価される)
methods: {
    increment() {
        this.num++;
    }
},
// 監視プロパティ
watch: {
    // 関数名は監視するプロパティ名
    num(newValue, oldValue) {
        this.watchStr = `${oldValue} -> ${newValue}`;
    }
},

○結果
Vue_Starter.png

form要素との連携(v-bind、v-model)

inputタグのform要素と同期してdataを操作できます。

html部

<div id="app">
    <!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) -->
    <h2>v-model(双方向同期)</h2>
    <input type="text" v-model="message">
    <p>{{message}}</p>

    <select v-on:input="selectedItem = $event.target.value;">
        <option selected="0" v-for="item in listItems">{{item}}</option>
    </select>
    <p>入力値:{{selectedItem}}</p>

    <!-- v-bind:r="radius" は :r="radius" と省略してもOK -->
    <h2>v-bind(片方向同期)</h2>
    <input type="range" v-model="radius" max="100" min="0">
    <p>radius = {{radius}}</p>
    <svg viewbox="0 0 300 300" width="300" height="300">
        <circle v-bind:r="radius" cx=150 cy=150></circle>
    </svg>
</div>

JavaScript部

data() {
    return {
        // object 形式でプロパティを記述していく
        message: 'hello vue',
        selectedItem: null,
        listItems: [
            "item1",
            "item2",
            "item3",
        ],
        radius: 10,
    };
},

○結果

Vue_Starter.png

Vue CLI を使ったWebアプリ(SPA)の作成

ここからfront-end、back-end に分けてWebアプリ(のようなもの)を作っていきます。
まずは、front-end側から作り始めます。

プロジェクトフォルダ作成

お好きなところにvue-spa-sampleという名前でフォルダを作ります。

vue/cliのインストール

vue-spa-sampleフォルダ内でコマンドラインを立ち上げます。
以下のコマンドでVue CLI をグローバルへインストールします。

npm i -g @vue/cli

なお、npm のコマンドは以下が纏まっていてみやすかったです。
npm 入門

インストールが終了したら以下のコマンドでバージョンが返ってくることを確認します。

vue -V

front-end プロジェクトの作成

続けてコマンドラインから

vue create front

でプロジェクトを作成します。
front の部分はプロジェクト名になるので、
本来はお好きな名前をつけていただいてOKです。

[2019/11/18 修正]

axios が上手く動かなかったので、TypeScript で記述して行きます。
原因わかりましたらまた更新します。

以前のここのセットアップ方法はJavaScript版のものなので、
TypeScript版へ修正します。

[2019/11/20 修正]
JavaScript版でも動作確認できました。
JavaScript版でこのハンズオンを進める場合は、以下のPlease pick a preset:default(babel, eslint)を選択します。(選択するとプロジェクトのダウンロードがすぐに始まります)。
TypeScriptを使用する場合は以下の流れで設定して行きます。

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24.png
↓キーを押下して Manually select features を選択します。

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24.png

BabelTypeScriptLinter / Formatter を選択し、Enterを押下します。
ちなみに Babel -> 1 、 TypeScript -> 2 のように、
数字キーがそれぞれの要素に対応しています。

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24.png

クラススタイルで記述するか?の質問です。 n を押下します。
クラススタイルは記述しやすいですが、以下のデメリットがあるため、私は通常の記述スタイルをおすすめしています。

  • <template> タグ内で補完が効かない(vscode,vetur 使用の場合)
  • 挙動が異なる場合がある
  • ググってヒットする情報のほとんどがJavaScriptの記述方式であり、クラススタイルを採用した場合は読み換える必要がある。

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24.png

y を押下

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24.png

ESLint with error prevention only を選択して押下

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24_と_「Vue_Web_App_Tutorial」を編集_-_Qiita.png

Lint on save を選択して押下

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24_と_「Vue_Web_App_Tutorial」を編集_-_Qiita.png

In dedicated config files を選択して押下

pechi_—_node____nvm_versions_node_v12_13_0_bin_vue_create_test_—_80×24_と_「Vue_Web_App_Tutorial」を編集_-_Qiita.png

n を選択して押下。

パッケージのダウンロードが始まります。
全て終了したら、表示されているように以下のコマンドを入力してdev serverを立ち上げます。

cd front
npm run serve

dev server が立ち上がったら、ブラウザからhttp://localhost:8080へ接続します。
以下のような画面が表示されます。

front_と_front_—_node_◂_npm_TERM_PROGRAM_Apple_Terminal_NVM_CD_FLAGS__TERM_xterm-256color_—_80×24.png

確認したら、vscodeでfrontフォルダを開きます。
これからVueのSFCファイルを見て行きますが、ハイライトや補完等の機能が使えるように、
エクステンションでveturを検索し、インストールしておきます。

単一ファイルコンポーネント(SFC)とコンポーネント

Vue CLI で作られたプロジェクトはSFCに対応しています。
SFCとは、コンポーネント(Vueの描画領域を部分的に記述し、部品化したもの)をtemplatescriptcssのそれぞれのタグに分けて記述したものです。

現在のプロジェクトで言うと、src/App.vueが画面全体を描画しているコンポーネントで、
src/components/HelloWorld.vueは部分的リンクの部分を描画している部品になります。

コードで見るとこんな感じです。

全画面_2019_11_16_15_23.png

コンポーネントを作ってみる

src/components/内にMainPage.vueという名前でSFCを作ります。
以下のようにコードを記述します。
(以降のコードはTypeScriptを選択した場合の記述スタイルです。JavaScriptを選択した場合は、
<script lang="ts"><script> に変更してください。それ以外の部分は共通で動作します。)

src/components/MainPage.vue
<template>
  <div>
      <h1>自作コンポーネントのページです</h1>
      <h2>hello {{name}}</h2>
  </div>
</template>

<!-- JavaScriptの場合は以下のように lang="ts" を記述しない-->
<!-- <script> -->
<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
    name: 'main-page',
    data() {
        return {
            name: 'vue', // 好きな名前を入れてください
        }
    }
});
</script>

<style>

</style>

ファイルを保存したら、src/App.vueを以下のように修正します。

src/App.vue
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <!-- コメント化 -->
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <!-- 追加 -->
    <main-page/>
  </div>
</template>

<script lang="ts">
// import HelloWorld from './components/HelloWorld.vue' // <- コメント化
import MainPage from "./components/MainPage.vue"; // <- 追加、.vue を忘れないで

export default {
  name: 'app',
  components: {
    // HelloWorld // コメント化
    MainPage // 追加
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

ファイルを保存します。
再度先ほどブラウザで開いたhttp://localhost:8080を見るとオートリロードがかかって
以下のようになっていると思います。(なっていなかったら手動でリロードしてください)

front_と_App_vue_—_front.png

MyButton コンポーネントの追加

src/components/内にMyButton.vueという名前でオリジナルのボタンを作って見ます。
私はデザインはできないので、以下のサイト様からパク参考にさせて頂きました。
CSSで作る!押したくなるボタンデザイン100(Web用)

src/components/MyButton.vue
<template>
  <a href="#" class="btn-square" @click="change()">{{label}}</a>
</template>

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
    name: 'my-button',
    props: [
        'label'
    ],
    methods: {
        change() {
            this.$emit('label-update', 'changed');
        }
    }
})
</script>

<style scoped>
.btn-square {
  display: inline-block;
  padding: 0.5em 1em;
  text-decoration: none;
  background: #668ad8;/*ボタン色*/
  color: #FFF;
  border-bottom: solid 4px #627295;
  border-radius: 3px;
}
.btn-square:active {
  /*ボタンを押したとき*/
  -webkit-transform: translateY(4px);
  transform: translateY(4px);/*下に動く*/
  border-bottom: none;/*線を消す*/
}
</style>

style タグ内に付いているscopedは、SFCファイル独自のもので、
記述すると定義されているCSSをこのコンポーネントのみに適用することができます。

また、Vueオブジェクト内のpropsは、コンポーネントの呼び出し側からデータを受け取ることのできるプロパティです。また、methods内のthis.$emitは、このコンポーネント呼び出すイベントを定義しています。
具体的には、ボタンが押下されると、label-updateイベントが起き、呼び出し元の親コンポーネントへ変更された値を通知します。
(Vueでは子コンポーネントがporpを勝手に書き換えることはNGとされており、このようにイベントとして親コンポーネントに通知を送り、親オブジェクトに変更をかけてもらうようにしています。)

MainPage.vueを以下のように変更し、結果を確認して見ます。

src/components/MainPage.vue
<template>
  <div>
      <h1>自作コンポーネントのページです</h1>
      <h2>hello {{name}}</h2>
      <!-- 追加   -->
      <my-button :label="btnName" @label-update="updateName"/>
  </div>
</template>

<script lang="ts">
import Vue from 'vue';
import MyButton from "./MyButton.vue"; // 追加

export default Vue.extend({
    name: 'main-page',
    components: {
        MyButton
    },
    data() {
        return {
            name: 'vue', // 好きな名前を入れてください
            btnName: 'Myボタン' // 追加
        }
    },
    // 追加
    methods: {
        updateName(val: string) {
            this.btnName = val;
        }
    }
});
</script>

<style>

</style>

front_と_MainPage_vue_—_front.png

5. WebAPIの作成

express を使ってWebAPIを作成します。
vue-spa-sampleフォルダ内にbackフォルダを作り、その中でコマンドラインを立ち上げます。
以下のコマンドを順に打ち込んで行きます。

npm init -y
npm i -S express cors body-parser

インストールが終わったら、vscodeでbackフォルダを開きます。
back/srcフォルダ内にrouterフォルダを作成し、その中にroot.jsファイルを作成します。

src/router/root.js
const express = require("express");
const router = express.Router();

router.get('/', (req/* リクエスト */, res/* レスポンス */) => {

    // json でレスポンス
    res.send({
        message: 'res from express'
    });
});

module.exports = router;

back/srcフォルダ内にapp.jsファイルを作成し、以下のコードを記述します。

src/app.js
const express = require("express");
const bodyparser = require("body-parser");
const cors = require("cors");
const indexRouter = require("./router/root");


const app = express();

// CORS 制限の解除
app.use(cors());

// 通信にJsonを使用する
app.use(bodyparser.json())

// /にindexRouterをルーティング
app.use('/', indexRouter);


module.exports = app; // appを公開

back/srcフォルダ内にindex.jsファイルを作成し、以下のコードを記述します。

src/index.js
const app = require("./app");

const port = 3000;

app.listen(port, () => {
    // port listen を始めた時に実行される処理
    console.log(`express listen port ${port}`);
});

全て保存したら、コマンドラインで以下のコマンドを実行

node ./src/index.js

サーバーが起動したら、ブラウザからhttp://localhost:3000にアクセスする。
以下のようになったらOK。

localhost_3000.png

6 WebアプリとWebAPI で通信

これまで作ってきたfront-end と back-end を連携して行きます。

front側のdev-serverをctrl + cで終了し、以下のコマンドを入力する

npm i -S axios

axiosがインストールされたら、再度

npm run serve

でdev-server を起動して起きます。

axiosで通信する

src/components/MainPage.vue を以下のように修正します。

src/components/MainPage.vue
<template>
  <div>
      <h1>自作コンポーネントのページです</h1>
      <h2>hello {{name}}</h2>
      <my-button :label="btnName" @label-update="updateName"/>

      <!-- 追加   -->
      <div>
          <p>{{message}}</p>
          <button @click="getExpress()">get express root</button>
      </div>
  </div>
</template>

<script lang="ts">
import Vue from 'vue';
import MyButton from "./MyButton.vue";
import * as axios from "axios";

export default Vue.extend({
    name: 'main-page',
    components: {
        MyButton
    },
    data() {
        return {
            name: 'vue', // 好きな名前を入れてください
            btnName: 'Myボタン',
            message: 'no message'  // 追加
        }
    },
    methods: {
        updateName(val: string) {
            this.btnName = val;
        },
        // 追加
        getExpress() {
            axios.default.get('http://localhost:3000').then((responce) => {
                this.message = responce.data.message;
            });
        }
    }
});
</script>



<style>

</style>

http://localhost:8080にアクセスしてget express rootのボタンを推してみる。
no message が res from express に変わったら成功。localのexpressサーバーと通信できてます。

hangouts_google_com_が画面を共有しています。_と_front2.png

今後やって行くこと


Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした