Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9055

Vue Web App Tutorial

$
0
0

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
constmsg='hello world';console.log(msg);
node ./hello.js

=> hello world

変数の型(es6)

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

Number

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

constpi=3.14;varindex=1;

String

文字列型

constmessage='hello world';// '' で囲むvarname="huga";// "" もOK

Boolean

true or false

constflg=true;console.log(flg);// => trueconsole.log(!flg);// => falseif(flg){console.log('flg is true');// => flg is true}

Array(配列)

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

// 宣言方法constarr=[];// arr => [](空配列)letvalues=newArray();// values => [](空配列)constarr2=[1,2,3];// arr2 => [1,2,3]constvalues2=newArray(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]);// => 1console.log(arr[1]);// => 2// 要素の取り出しconsole.log(arr.pop());// => 2console.log(arr);// => [1]

Function

関数

// 通常?の宣言functiontwice(num){returnnum*2;}// ラムダ式constjoinStr=(str1,str2)=>{returnstr1+str2;};console.log(twice(2));// 4console.log(joinStr("hello ","world"));// hello world

Object

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

// 宣言constobj={};constobj2=newObject();// 要素の追加obj["id"]=1;obj.name="huga";obj.getName=function(){returnthis.name;};console.log(obj);// => { id: 1, name: 'huga', getName: [Function] }// 要素の参照console.log(obj["id"]);// => 1console.log(obj.name);// => hugaconsole.log(obj.getName());// => huga

null, undefined

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

const, let, var

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

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

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

制御構文

if

分岐処理

letflg=false;if(flg){// 実行されない}else{// 実行される}if(flg!=true){// 実行される}

for

繰り返し処理

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

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

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

4. HTML

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

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

<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><metahttp-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><tableborder="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><tableborder="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>

〇 結果

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

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

入力要素

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

<body><div><h3>テキストボックス </h3><inputtype="text"></div><div><h3>テキストボックス(パスワード) </h3><inputtype="password"></div><div><h3>ボタン </h3><inputtype="button"value="ボタンです"></div><div><h3>チェックボックス </h3>チェックしてください<inputtype="checkbox"></div><div><h3>ラジオボックス </h3><inputtype="radio"name="my-radio"value="radio-item1">ラジオ1
        <inputtype="radio"name="my-radio"value="radio-item2">ラジオ2
        <inputtype="radio"name="my-radio"value="radio-item3">ラジオ3
    </div><div><h3>コンボボックス </h3><select><optionselected="0">選択アイテム1</option><option>選択アイテム2</option><option>選択アイテム3</option><option>選択アイテム4</option></select></div><div><h3>スライダー</h3><inputtype="range"></div><div><h3>カラーピッカー </h3><inputtype="color"></div><div><h3> FILE API </h3><inputtype="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><htmllang="ja"><head><metacharset="utf-8"><title>Vue Starter</title></head><body><divid="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 オブジェクトvarapp=newVue({el:'#app',data(){return{// object 形式でプロパティを記述していく};},// 算出プロパティ(キャッシュされる)computed:{},// 監視プロパティwatch:{},// 関数(キャッシュされない、都度評価される)methods:{},// ライフサイクルフック ---------------------------------------------------// https://jp.vuejs.org/v2/api/#beforeUpdatebeforeCreate(){},created(){},mounted(){},beforeUpdate(){},updated(){},activated(){},deactivated(){},beforeDestroy(){},destroyed(){}// ライフサイクルフック ---------------------------------------------------});</script></body></html>
プロパティ名説明
elVueでレンダリングするHTML DOMのidを記述する。
dataレンダリングで参照されるプロパティ。画面描画のもとになる
computeddataを元に算出されるプロパティ。いわゆるgetter
watch登録されているdataの変化を監視し、変更があった場合の処理を記述する
methods関数。ボタンのクリックイベント等、特定のイベントにフックして実行する処理を記述する

ライフサイクルフック

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

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

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

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

〇結果

image.png

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

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

<divid="app"><!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) --><p>Array のレンダリング</p><ul><liv-for="(item, index) in itemList">{{index}}: {{item}}</li></ul><p>Object のレンダリング</p><tableborder="1"><thead><th>key</th><th>value</th></thead><tbody><trv-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オブジェクトを以下のように修正します。

<divid="app"><!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) --><buttonv-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オブジェクトを以下のように修正します。

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

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

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

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

<divid="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(){// 二乗の数を返すreturnMath.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部

<divid="app"><!-- このエリアにVue 形式の HTMLを記述していく(描画DOMエリア) --><h2>v-model(双方向同期)</h2><inputtype="text"v-model="message"><p>{{message}}</p><selectv-on:input="selectedItem = $event.target.value;"><optionselected="0"v-for="item in listItems">{{item}}</option></select><p>入力値:{{selectedItem}}</p><!-- v-bind:r="radius" は :r="radius" と省略してもOK --><h2>v-bind(片方向同期)</h2><inputtype="range"v-model="radius"max="100"min="0"><p>radius = {{radius}}</p><svgviewbox="0 0 300 300"width="300"height="300"><circlev-bind:r="radius"cx=150cy=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 プロジェクトの作成

続けてコマンドラインから
bat
vue create front

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

? Please pick a preset:

default (babel, eslint) を選択します。
パッケージのダウンロードが始まります。
全て終了したら、表示されているように以下のコマンドを入力して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を作ります。
以下のようにコードを記述します。

src/components/MainPage.vue
<template><div><h1>自作コンポーネントのページです</h1><h2>hello {{name}}</h2></div></template><scriptlang="ts">importVuefrom'vue';exportdefaultVue.extend({name:'main-page',data(){return{name:'vue',// 好きな名前を入れてください}}});</script><style></style>

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

src/App.vue
<template><divid="app"><imgalt="Vue logo"src="./assets/logo.png"><!-- コメント化 --><!-- <HelloWorldmsg="Welcome to Your Vue.js App"/> -->
    <!-- 追加 --><main-page/></div></template><scriptlang="ts">// import HelloWorld from './components/HelloWorld.vue' // <-コメント化importMainPagefrom"./components/MainPage.vue";// <-追加、.vueを忘れないでexportdefault{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><ahref="#"class="btn-square"@click="change()">{{label}}</a></template><scriptlang="ts">importVuefrom'vue';exportdefaultVue.extend({name:'my-button',props:['label'],methods:{change(){this.$emit('label-update','changed');}}})</script><stylescoped>.btn-square{display:inline-block;padding:0.5em1em;text-decoration:none;background:#668ad8;/*ボタン色*/color:#FFF;border-bottom:solid4px#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><scriptlang="ts">importVuefrom'vue';importMyButtonfrom"./MyButton.vue";// 追加exportdefaultVue.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フォルダを作り、その中でコマンドラインを立ち上げます。
以下のコマンドを順に打ち込んで行きます。
bat
npm init -y
npm i -S express cors body-parser

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

src/router/root.js
constexpress=require("express");constrouter=express.Router();router.get('/',(req/* リクエスト */,res/* レスポンス */)=>{// json でレスポンスres.send({message:'res from express'});});module.exports=router;

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

src/app.js
constexpress=require("express");constbodyparser=require("body-parser");constcors=require("cors");constindexRouter=require("./router/root");constapp=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
constapp=require("./app");constport=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 server

で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><scriptlang="ts">importVuefrom'vue';importMyButtonfrom"./MyButton.vue";import*asaxiosfrom"axios";exportdefaultVue.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

今後やって行くこと



Viewing all articles
Browse latest Browse all 9055

Latest Images

Trending Articles