Vue.js のお勉強(備忘録)
目次
Vue.jsとは
javascriptのフレームワークでSPA(SinglePageApplication)が作れる。
HTML・CSS・JavaScriptのみで構成され、サーバーとの通信を減らせるため動作が比較的軽い。
Vue.jsについて自分なりのまとめ
・component(コンポーネント)を使い(ヘッダー,フッター,メインコンテンツなど)機能分けして管理する
・UIのデザインで困ったらVuetifyを検討する
・中〜大規模の場合Vuexで状態管理する
・公式リファレンスが充実しているので困ったら必ず確認する
・見られない書き方はディレクティブの省略記法である可能性があるので確認
・APIを叩く場合、form送信(json形式となる)する場合、ファイルアップロードなどには axios を使う
・v-modelで入力フォームの入力値の保持やセレクトボックスの選択肢などを定義できる
・Routerを親と子の入れ子にすると画面遷移でのデータを保持できる
・Vue.jsではレンダリング処理をクライアント側で行うためSEO対策するならNuxt.jsを使う
Vue-Cliで環境構築
Vue-CliはVueプロジェクトの初期セットアップで導入する環境を簡単に作成できるツール
#VueCLIをインストール
1 |
npm install -g @vue/cli |
#プロジェクトの作成
1 |
vue create vue-project |
プロジェクトの作成方法を選択
1 |
Manually select features |
必要なプリセットの選択
Babel - 最新のJS構文を環境に応じたバージョンに変換する
Router - 画面遷移など
Vuex - 状態管理パターン
CSS-Preprocessors - Scss
#Vue.jsのフォルダ構成
node_modules - リクエストを実行(デフォルトはGET)
public - imgフォルダなど
src - ソースコード
.gitignore - gitに含めないディレクトリ
babel.config - babelの設定
package.json - 関連パッケージスクリプトの定義
package-lock.json - インストールパッケージのバージョン定義
ディレクティブ(公式リンク)
以下については、dataに代入する事で反映できる。
#v-text
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span v-text="msg"></span> <!-- 同じ --> <span>{{msg}}</span> <script> export default { data() { return { msg: 'テキスト表示' } } } </script> |
#v-html
1 2 3 4 5 6 7 8 9 10 11 |
<div v-html="htmlmsg"></div> <script> export default { data() { return { htmlmsg: '<p>htmlタグを含めた<br>文章でもタグが適用される</p>' } } } </script> |
#v-show
初期描画コストが高い。頻繁に何かを切り替える必要がある場合に使用する。
v-showディレクティブはcssのdisplay要素を切り替える。
1 2 3 4 5 6 7 8 9 10 11 |
<h1 v-show="isShow">Hello</h1> <script> export default { data() { return { isShow01: true, } } } </script> |
#v-if
#v-else
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<div id="app"> //論理データの場合 <p v-if="isShow01">表示される。</p> <p v-else>表示されない。</p> //計算式の場合 <div v-if="Math.random() > 0.5"> <p v-else>表示されない。</p> </div> <script> export default { data() { return { isShow01: true, } } } </script> |
#v-else-if
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div> <script> export default { data() { return { type: 'B', } } } </script> |
#v-for
selectボックスの選択肢などに使った。属性keyとvalueを使い配列の要素を取得する。
1 2 3 4 5 6 7 8 9 10 11 |
// <div v-for="item in items" :key="item.id"> {{ item.text }} </div> // 生年月日の月の選択に使う場合の例 <select name="birth_month" v-model="p_arr.sub_d.birth_month" v-on:change="modify" class="custom-select"> <option v-for="birth_month in p_arr.sub_d.birth_months" name="birth_month" v-bind:value="birth_month" v-bind:key="birth_month"> {{ birth_month }} </option> </select> |
#v-on
2.4.0 からは、v-on は引数なしでイベント/リスナーのペアのオブジェクトへのバインディングもサポートしている。
修飾子の種類については公式サイトで確認。
以下省略記法
1 2 3 4 5 6 7 8 9 10 |
<video id="video" @play="onPlay"></video> <script> export default { methods: { onPlay() { } } } </script> |
以下submit で使用した場合
.prevent でsubmit のデフォルト挙動を防いで実行する
.preventはevent.preventDefault()を呼び出す
1 2 3 4 5 6 7 8 9 10 |
<form @submit.prevent="checkFrom" class="form-horizontal reginp"> <script> export default { methods: { checkFrom() { } } } </script> |
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<!-- メソッドハンドラ --> <button v-on:click="doThis"></button> <!-- 動的イベント (2.6.0 以降) --> <button v-on:[event]="doThis"></button> <!-- インラインステートメント --> <button v-on:click="doThat('hello', $event)"></button> <!-- 省略記法 --> <button @click="doThis"></button> <!-- 動的イベントの省略記法 (2.6.0 以降) --> <button @[event]="doThis"></button> <!-- イベント伝播の停止 --> <button @click.stop="doThis"></button> <!-- デフォルト挙動を防ぐ --> <button @click.prevent="doThis"></button> <!-- 式なしでデフォルト挙動を防ぐ --> <form @submit.prevent></form> <!-- 修飾子の繋ぎ合わせ --> <button @click.stop.prevent="doThis"></button> <!-- キーエイリアスを使ったキー修飾子 --> <input @keyup.enter="onEnter"> <!-- キーコードを使ったキー修飾子 --> <input @keyup.13="onEnter"> <!-- 最大1回、クリックイベントはトリガされます --> <button v-on:click.once="doThis"></button> <!-- オブジェクト構文 (2.4.0+) --> <button v-on="{ mousedown: doThis, mouseup: doThat }"></button> |
#v-bind
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<!-- 属性を束縛 --> <img v-bind:src="imageSrc"> // 例: data : { imageSrc: '../img/aaa.jpg', } <!-- 動的な属性名 (2.6.0 以降) --> <button v-bind:[key]="value"></button> <!-- 省略記法 --> <img :src="imageSrc"> // 例: data : { imageSrc: '../img/aaa.jpg', } <!-- 動的な属性名の省略記法 (2.6.0 以降) --> <button :[key]="value"></button> <!-- インライン文字列連結 --> <img :src="'/path/to/images/' + fileName"> <!-- クラスバインディング --> <div :class="{ red: isRed }"></div> <div :class="[classA, classB]"></div> <div :class="[classA, { classB: isB, classC: isC }]"> <!-- スタイルバインディング --> <div :style="{ fontSize: size + 'px' }"></div> <div :style="[styleObjectA, styleObjectB]"></div> <!-- 属性のオブジェクトのバインディング --> <div v-bind="{ id: someProp, 'other-attr': otherProp }"></div> <!-- prop 修飾子による DOM 属性バインディング --> <div v-bind:text-content.prop="text"></div> <!-- prop バインディング。"prop" は my-component 内で宣言される必要があります --> <my-component :prop="someThing"></my-component> <!-- 親のプロパティの子コンポーネントに渡す ---> <child-component v-bind="$props"></child-component> <!-- XLink --> <svg><a :xlink:special="foo"></a></svg> |
例: HTML クラスのバインディング
パターン1
※既にクラス名staticを指定している
1 2 3 4 5 6 7 8 9 10 11 |
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div> <script> export default { data: { isActive: true, hasError: false } } } </script> |
↓ 描画結果
1 |
<div class="static active">/div> |
パターン2
※インラインではない場合
1 2 3 4 5 6 7 8 9 10 11 |
<div v-bind:class="classObject"></div> <script> export default { classObject: { active: true, 'text-danger': false } } } </script> |
↓ 描画結果
1 |
<div class="active">/div> |
#v-model
form の input 要素 や textarea 要素、 select 要素に双方向 (two-way) データバインディングを作成する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
//テキストフィールド <input v-model="textfld" type="text" /> //チェックボックス <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> //ラジオボタン <input type="radio" id="one" value="One" v-model="picked"> <label for="one">One</label> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Two</label> //セレクトボックス <select v-model="selected"> <option v-for="option in options" v-bind:value="option.value"> {{ option.text }} </option> </select> data: { textfld: "", checkedNames: [], picked: "", selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } |
修飾子:
#.lazy
引用: デフォルトでは、 v-model
は各 input
イベント (上記の IME 確定前を除いて) 後に、データと入力を同期します。
change
イベント の後に 同期するように変更するために lazy
修飾子を追加することができます
1 |
<input v-model.lazy="msg"> |
#.number
入力値を自動的にnumber型に変換します
1 |
<input v-model.number="age" type="number"> |
#.trim
ユーザーの入力値から自動的に空白をを取り除きます
1 |
<input v-model.trim="msg"> |
#v-slot
※※※※※ 後ほど記載 ※※※※※
1 2 3 4 5 |
ああああああ ああああああ ああああああ ああああああ ああああああ |
#v-pre
コンパイルがスキップされる。ソースコードなどを記載してもスキップされる。
1 |
<span v-pre>{{ this will not be compiled }}</span> |
↓ 描画結果
1 |
{{ this will not be compiled }} |
#v-cloak
v-cloak で囲った箇所はコンパイルが完了するまで不可視となる
css:
1 2 3 |
[v-cloak] { display: none; } |
html:
1 2 3 |
<div v-cloak> {{ message }} </div> |
特別な属性(公式リンク)
#key
v-forと合わせて使うことが多い説明は#v-forで確認
#ref
$refs を使う事で、htmlにてref属性をつけた要素を参照することができる。
リストレンダリングについても要素番号を指定して参照できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div ref="divref01"></div> <video ref="videoref01"></video> <div v-for="item in items" :key="item.id" ref="itemlist"> {{ item.text }} </div> <script> export default { mounted: { divref01 = this.$refs.divref01 videoref01 = this.$refs.videoref01 itemlist01 = this.$refs.itemlist[0] } } </script> |
#is
componentを切り替えることができる
1 |
<component v-bind:is="currentTabComponent"></component> |
組み込みコンポーネント(公式リンク)
#component
動的コンポーネント
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<button v-for="tab in tabs" v-bind:key="tab.name" v-bind:class="['tab-button', { active: currentTab.name === tab.name }]" v-on:click="currentTab = tab" > {{ tab.name }} </button> <component v-bind:is="currentTab.component" class="tab"></component> <script> var tabs = [ { name: "Home", component: { template: "<div>Home component</div>" } }, { name: "Posts", component: { template: "<div>Posts component</div>" } }, { name: "Archive", component: { template: "<div>Archive component</div>" } } ]; new Vue({ el: "#dynamic-component-demo", data: { tabs: tabs, currentTab: tabs[0] } }); </script> |
#transition
CSSアニメーションを扱う際に使用
1 |
<span style="color: #222222; font-family: monospace, monospace;"><span style="background-color: #e9ebec;"><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span>保留<span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span><span style="color: #222222; font-family: monospace, monospace;">※</span></span></span> |
#transition-group
保留
1 |
保留 |
#keep-alive
保留
1 |
保留</code><code> |
Vuex
componentを分かりやすく管理する。
中〜大規模のアプリケーションに最適。
Nuxt.js
主に5点の利点がある。
・SSR 『Server Side Rendering(サーバサイドレンダリング)』という機能を利用してレンダリング処理をサーバー側で行うため、サイトの表示速度があがる。
ただその分、サーバーにNode.jsの環境整備及びCPUに負荷がかかるためキャッシュの管理に気をつける必要がある
・ディレクトリ構成が予めされているため、ファイルの保存先に迷わずに済む
・Code Splitting によって各ページに必要なjavascriptのみ渡される
・ルーティングを自動で設定してくれる
・SEO対策にも有効で、vue-metaによるSEO対策ができる
Vuetify
Vue UI ライブラリ
画面のデザインに必要なサンプルが豊富に用意されている。
webpack
webpackとはモジュールバンドラーである。
複数のモジュールの依存関係を解決して一つにまとめるものである。
ブラウザ/サーバー間での通信プロトコルであるHTTP/1.1では一度に処理できるリクエストの数に限りがあるので、
リクエストの数をなるべく一つに減らすことで表示速度のパフォーマンスを向上させることができる。
メモリリーク
ライブラリを使った場合、メモリリークが起こる可能性がある。
その場合、意図的にメモリの開放をすることで解決する
beforeDestroy:Vueインスタンス破棄される前に呼び出される
destroyed:Vueインスタンスが破棄された後に呼び出される
axios を利用した API の使用
axiosで取得したデータはreponseで取得できる 呼び出しがうまくいかない場合はcatchでエラーハンドリング
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
new Vue({ el: '#app', data () { return { info: null, loading: true, errored: false } }, filters: { currencydecimal (value) { return value.toFixed(2) } }, mounted () { axios .get('https://api.coindesk.com/v1/bpi/currentprice.json') .then(response => { this.info = response.data.bpi }) .catch(error => { console.log(error) this.errored = true }) .finally(() => this.loading = false) } }) |
VS Code によるデバッグ(Nuxt.js)
Nuxt.jsでサーバーレンダリングを行ったソースコードはブラウザに表示される際に最適化される為、
最適化される前のソースコードと紐付ける為にsourcemapを利用する
・Vusial Studio Code (VS Code)のextensionとしてDebugger for Chromeを追加する
・SourceMapを作成する
※SSR(サーバーレンダリング)ではない場合は、Vue.js devtoolsでもデバッグできる。
Vue Test Utils
Vue Test UtilsはJest、Karma、Mochaなどのテストランナーと組み合わせて使う。
単体テストが行える。