一、vue とは何か?#
練習時に使用、最新バージョン
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
本番時に使用、明確なバージョン番号のバージョンを使用し、予期しない問題を避ける
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
こんにちは世界
<div id="app">
{{message}}
</div>
<script>
var app = new Vue({
el: "#app",
data: {
message: 'こんにちは、世界'
}
})
</script>
1.v - ディレクティブ#
- v-bind--属性をバインドする
<div id="app-2">
<span v-bind:title="message">
マウスを数秒間ホバーして、ここに動的にバインドされたヒント情報を表示します!
</span>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'ページが読み込まれたのは ' + new Date().toLocaleString()
}
})
</script>
v-bind
は vue 特有の属性で、DOM にリアクティブな操作を適用します。
コンソールを開いて、app.message = "こんにちは"
と入力すると、ページの内容がこんにちは
に変わります。
また、app.message = false
と入力すると、内容が直接表示されなくなります。
vue 公式サイトの例:
<!-- 属性をバインドする -->
<img v-bind:src="imageSrc">
<!-- 動的属性名 (2.6.0+) -->
<button v-bind:[key]="value"></button>
<!-- 短縮形 -->
<img :src="imageSrc">
<!-- 動的属性名の短縮形 (2.6.0+) -->
<button :[key]="value"></button>
<!-- インライン文字列結合 -->
<img :src="'/path/to/images/' + fileName">
<!-- classバインディング -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- styleバインディング -->
<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>
<!-- $propsを使って親コンポーネントのpropsを子コンポーネントに渡す -->
<child-component v-bind="$props"></child-component>
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
- v-if--要素の表示・非表示を制御する
先ほど書いたように、app.message = false
を使うことで、message
が表す内容を非表示にすることができますが、制御できるのはv-for
で導入した内容だけで、要素を直接非表示にすることはできません。
実際、vue には要素の表示・非表示を制御するための専用のディレクティブがあります--v-if
です。
<div id="app">
<span v-if="show">
{{message}}
</span>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
message: 'こんにちは、世界',
show: true
}
})
</script>
要素にディレクティブv-if = "show"
をバインドし、data 内でshow
のブール値を制御します。true で表示、false で非表示です。
同様の機能を持つディレクティブv-show
もあり、式の真偽値に基づいて要素のdisplay
CSS プロパティを切り替えます。これもバインドされたブール値によって表示・非表示を制御します。
しかし、v-if
とv-show
にはいくつかの違いがあります
(1) v-if は要素がレンダリングされるかどうかを制御し、最終的に要素の表示・非表示を制御します。切り替え頻度が低い場合に適しています。
(2) v-show は表示・非表示に関わらずレンダリングされ、その後ブール値をバインドしてdisplay: none
属性を適用します。切り替え頻度が高い場合に適しています。
注意:
v-show
は<template>
要素をサポートしておらず、v-else
もサポートしていません。
組み合わせて使用する
v-else
とv-else-if
v-else
を使用することでv-if
の効果を得ることができますが、必ずv-if
と組み合わせて使用する必要があります。例えば:
<div v-if="1>2">
こんにちは
</div>
<div v-else>
こんにちは
</div>
もしv-if
が成立しなければ、v-else
が実行され、つまりv-else
内の内容が表示されます。
少し JavaScript のif文
の感じがしますね。
v-else-if
の使い方もほぼ同じで、必ずv-if
とv-else
と組み合わせて使用します。
- v-for--配列をループしてページに表示する
v-for
は vue のコアディレクティブの一つで、主にアイテムリストをレンダリングするために使用されます。
<div id="app">
<div v-for="item in list">{{item.message}}</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
list: [
{message: 'html'},
{message: 'css'}
]
}
})
</script>
リストデータを直接ループして出力できます。
そして、コンソールでpush()
を使って新しいリスト項目を追加することもできます。
app.list.push({message: "js"})
vue のデータ操作は本当に素晴らしいです。
v-for
とv-if
を同時に使用することは推奨されません。なぜなら、v-for
はより高い優先度を持っているからです。
- v-on--イベントリスナーをバインドする
イベントをバインドするために、v-on
を使って div にクリックイベントをバインドしました。注意点として、reverseMessage
メソッド内でアプリケーションの状態を更新しましたが、DOM に直接触れることはせず、vue を通じて処理します。コードを書く際にはロジック層にのみ集中すれば良いのです。
v-on:click="messagenone"
、その後methods
内にイベントメソッドを書きます。
<div id="app">
<div v-on:click="messagenone" id="demo">{{message}}</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
message: 'こんにちは、世界'
},
methods: {
messagenone: function() {
var demo = document.getElementById('demo');
demo.innerHTML = ''
}
}
})
</script>
- v-model--データの双方向バインディング
vue はv-model
ディレクティブも提供しており、フォーム入力とアプリケーションの状態との間で簡単に双方向バインディングを実現できます。
使用シーン:input、select、textarea、コンポーネント
<div id="app">
<div>{{message}}</div>
<input type="text" v-model="message">
</div>
<script>
var app = new Vue({
el: "#app",
data: {
message: 'こんにちは、世界'
}
})
</script>
- v-text で要素の内容を更新する
<div id="app">
<div v-text="message"></div>
<div>{{message}}</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'こんにちは、世界'
}
})
</script>
上の div と下の div の内容は常に一致して変化します。
- v-html--要素の innerHTML を更新する
使用は推奨されません。ウェブサイト上で動的に HTML をレンダリングすることは非常に危険で、XXS攻撃
を引き起こす可能性があります。ユーザーが提出した内容には使用しないでください。もしv-html
を使用する必要がある場合は、コンポーネントを使用して代替することを検討してください。
- v-pre
バインドされた要素とその子要素のコンパイルをスキップし、元の内容を直接表示します。
指令のないノードをスキップしてコンパイルせず、直接内容を表示することで、ページの応答を速めます。
- v-cloak
コンパイルが完了していない間、テンプレートが保持する状態です。
<style>v-cloak] {
display: none;
}</style>
<div v-cloak>
{{message}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'こんにちは、世界'
}
})
</script>
上記のコードは、ネットワークが悪い場合、{{message}}
テンプレートが表すこんにちは、世界
がまだコンパイルされていない場合、{{message}}
が非表示の状態にあることを示しています。コンパイルが完了すると、ページは直接こんにちは、世界
を表示します。
- v-once--一度だけレンダリング
このディレクティブがバインドされた要素とその子要素は一度だけレンダリングされ、その後のページの二度目のレンダリングでは静的リソースとして扱われ、スキップされます。パフォーマンスを最適化するために使用できます。
<div id="app">
<span v-once>{{message}}</span>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'こんにちは、世界',
}
})
</script>
使用シーン:フォームの送信。ユーザーがリクエストに対して迅速に応答しない場合の多重送信を防ぐことができます〜
2. コンポーネント化してアプリケーションを構築する#
コンポーネント化は vue のコアメカニズムの一つであり、小型で再利用可能なコンポーネントを使用して大規模なアプリケーションを構築することを可能にします。
vue では、コンポーネントは本質的に事前定義されたオプションを持つ vue インスタンスです。vue でコンポーネントを登録するのは非常に簡単です。
// todo-itemという新しいコンポーネントを定義する
Vue.component('todo-item', {
template: '<li>これはタスク項目です</li>'
})
var app = new Vue(...)
これで、別のコンポーネントテンプレートを構築するためにそれを使用できます。
<ol>
<!-- todo-itemコンポーネントのインスタンスを作成 -->
<todo-item></todo-item>
</ol>
しかし、これでは各タスク項目が同じテキストをレンダリングするだけで、あまり魅力的ではありません。親スコープからデータを子コンポーネントに渡すことができるはずです。コンポーネントの定義を修正して、props
を受け取れるようにしましょう。
Vue.component('todo-item', {
// todo-itemコンポーネントは現在
// "props"を受け取ります。これはカスタム属性のようなものです。
// このprops名はtodoです。
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
これで、v-bind
ディレクティブを使用して、タスク項目をループ出力する各コンポーネントに渡すことができます。
各 todo-item に todo オブジェクトを提供します。todo オブジェクトは変数であり、その内容は動的である必要があります。また、各コンポーネントにkey
を提供する必要があります。
<div id="app-7">
<ol>
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '野菜' },
{ id: 1, text: 'チーズ' },
{ id: 2, text: 'その他の食べ物' }
]
}
})
これは意図的に設計された例に過ぎませんが、アプリケーションを 2 つの小さな単位に分割することに成功しました。子単位はprop
インターフェースを介して親単位と良好にデカップリングされています。これにより、コンポーネントをさらに改善し、より複雑なテンプレートとロジックを提供できますが、親単位には影響を与えません。
大規模なアプリケーションでは、全体のアプリケーションをコンポーネントに分割することが必要です。これにより、開発がより管理しやすくなります。
<div id="app">
<app-nav></app-nav>
<app-view>
<app-sidebar></app-sidebar>
<app-content></app-content>
</app-view>
</div>