2.1 データバインディングのディレクティブ
データバインディングとは、データと描画を同期する仕組み。
属性にテンプレート変数を利用したい場合に利用するのがデータバインディングのディレクティブ。
2.1.1 ディレクティブとは
ディレクティブとはテンプレートブロックで HTMLタグ内に記述する v-で始まる属性のこと。
ディレクティブ | 役割 |
---|---|
v-bind | データバインディング |
v-on | イベント処理 |
v-model | 双方向データバインディング |
v-html | HTML文字列表示 |
v-pre | 静的コンテンツ表示 |
v-once | データバインディングを初回のみに制限 |
v-cloak | マスタッシュ構文非表示 |
v-if | 条件分岐 |
v-show | 表示/非表示 |
v-for | ループ処理 |
2.1.2 属性にデータバインドする v-bind
マスタッシュ構文が使えないタグの属性部分に対してテンプレート変数を利用するためのもの。
<script setup lang="ts">
import { ref } from 'vue'
const url = ref('https://vuejs.org/')
</script>
<template>
<p><a v-bind:href="url" target="_blank">Vue.jsのサイト</a></p>
<p><a :href="url" target="_blank">Vue.jsのサイト(省略系)</a></p>
<p><a v-bind:href="url + 'guide/introduction.html'" target="_blank">Vue.jsガイドのページ</a></p>
</template>
HTMLタグのよく使う属性一覧
タグ | 属性 | 属性値 | 解説 |
---|---|---|---|
すべて | id | 任意(半角英数とハイフン) | 固有名(重複使用不可) |
class | 任意(半角英数とハイフン) | 主別名(重複使用不可) | |
style | CSSの内容 | CSSの直接指定 | |
a | href | リンク先のURL | リンク先を指定 |
target | _blank | 別タブで開く | |
img | src | 画像ファイルのURL | 画像を表示させる |
alt | 任意(全角) | 画像の説明 | |
width | 半角英数 | 画像の幅 | |
height | 半角英数 | 画像の高さ | |
table | border | 1 | 線があることを示す |
td,th | colspan | 半角英数 | 横結合 |
rowspan | 半角英数 | 縦結合 | |
input | type | text | 一行テキストボックス |
radio | 一つだけ選択できる選択肢 | ||
checkbox | 複数選択できる選択肢 | ||
submit | 送信ボタン | ||
name | 任意(半角英数) | 項目グループに名前をつける | |
value | 任意(全角) | 入力内容を全角で送る | |
placeholder | 任意(全角) | テキストボックス内に文字を表示 | |
label | for | 任意(半角英数) | inputと結びつける |
v-bind の基本構文
v-bind:△△="〇〇"
要素の△△属性の値として、テンプレート変数〇〇の値を設定
属性のを記述する部分(△△)のことをディレクティブの引数(Arguments)という
v-bind の省略形
v-bind部分を省略し「:」(コロン)以降のみとする記述方法。
:href="url"
ソースコードの可読性という視点では省略しない方が良い。
v-bind の値には式が記述できる
v-bind:href="url + 'guide/intoroduction.html'"
記述できるのは式だけであり文は使用できない。
式(Expression)とは変数に代入できるような値を生成するコード片を指す。
文(Statement)とは処理の単位を表し、通常はセミコロンで区切られた行ごとのまとまりが文になる。
2.1.3 属性値のない属性へのバインド
HTMLタグの属性には、disabledやreadonlyなど属性値のないものがある。
属性値がない属性にv-bindを使う方法。
<script setup lang="ts">
import { ref } from 'vue'
const isSendButtonDisabled = ref(true)
</script>
<template>
<p><button type="button" v-bind:disabled="isSendButtonDisabled">送信</button></p>
</template>
disabled属性には値としてtrue/falseのboolean型を使用する。
2.1.4 バインドする属性をテンプレート変数として指定
v-bind の引数として指定する属性名をテンプレート変数とすることもできる。
<script setup lang="ts">
import { ref } from 'vue'
const widthOrHeight = ref('height')
const widthOrHeightValue = ref(100)
</script>
<template>
<p><img alt="VueLogo" src="./assets/logo.svg" v-bind:[widthOrHeight]="widthOrHeightValue" /></p>
</template>
v-bind の引数部分にブラケット [] があり、その中にテンプレート変数を記述している。
このように引数もテンプレート変数で指定する方法を動的引数(DynamicArguments)という。
2.1.5 複数の属性にまとめてバインドする方法
引数を指定しないでv-bindを使うと複数の属性をまとめてバインドできる。
<script setup lang="ts">
import { ref } from 'vue'
const imgAttributes = ref({
src: '/images/logo.svg',
alt: 'Vueのロゴ',
width: 75,
height: 75,
})
</script>
<template>
<p><img v-bind:="imgAttributes" /></p>
<p><img v-bind="imgAttributes" title="ロゴです!" /></p>
<p><img v-bind="imgAttributes" alt="ロゴです!" /></p>
</template>
テンプレート変数をオブジェクトにすると複数の属性をまとめてバインドできる。
引数を指定しない v-bind と通常の属性(title=”ロゴです!”)は混在できる。
引数を指定しない v-bind と通常の属性が同じもの(alt=”ロゴです!”)の場合、後にある記述が優先される。
2.1.6 style 属性へのバインディング
style 属性も属性のひとつなので v-bind:style という記述になるが、style属性にはスタイルプロパティとプロパティ値の組み合わせを複数記述できる。
style="color: whit; background-color: black;"
<script setup lang="ts">
import { ref, computed } from 'vue'
const msg = ref('こんにちは!世界')
const msgTextRed = ref('red')
const msgTextColor = ref('white')
const msgBgColor = ref('black')
const msgStyles = ref({ color: 'white', backgroundColor: 'black' })
const msgStyles2 = ref({ fontSize: '24pt' })
const msgStyles3 = ref({ color: 'pink', fontSize: '24pt' })
const textSize = computed((): string => {
const size = Math.round(Math.random() * 25) + 10
return `${size}pt`
})
</script>
<template>
<p v-bind:style="{ color: msgTextRed }">1:{{ msg }}</p>
<p v-bind:style="{ color: 'pink' }">2:{{ msg }}</p>
<p v-bind:style="{ fontSize: textSize }">3:{{ msg }}</p>
<p v-bind:style="{ color: msgTextColor, backgroundColor: msgBgColor }">4:{{ msg }}</p>
<p v-bind:style="{ color: msgTextColor, 'background-color': msgBgColor }">5:{{ msg }}</p>
<p v-bind:style="msgStyles">6:{{ msg }}</p>
<p v-bind:style="[msgStyles, msgStyles2]">7:{{ msg }}</p>
<p v-bind:style="[msgStyles, msgStyles3]">8:{{ msg }}</p>
<p v-bind:style="[msgStyles3, msgStyles]">9:{{ msg }}</p>
</template>
v-bind:style の記述の基本
テンプレート変数名ではなく波括弧 {} を記述し、その中にスタイルプロパティと設定値をコロンで区切る形で指定する。
v-bind:style="{color: msgTextRed}"
設定値として記述できるもの
設定値 | 内容 |
---|---|
テンプレート変数 | v-bind:style=”{ color: msgTextRed }” |
リテラル | v-bind:style=”{ color: ‘pink’ }” |
算出プロパティ | v-bind:style=”{ fontSize: textSize }” |
v-bind:style の値を複数指定する方法
カンマで区切る
v-bind:style="{color: msgTextColor, backgroundColor: msgBgColor}"
v-bind:style の記述方法の構文
v-bind:style="{スタイルプロパティ: 値, ・・・}"
属性値はオブジェクトリテラルの形式となっている。
スタイルプロパティはキャメル記法
スタイルプロパティは本来「background-color」のようにケバブ記法で記述すべきだが「backgroundColor」とキャメル記法になっている。
これは、v-bind:styleの属性値がオブジェクトリテラルで、オブジェクトのプロパティ名には「-」(ハイフン)記号が使えないため。
スタイルプロパティをケバブ記法で記述する方法
シングルクォーテーションで囲む
v-bind:style="{cokor: msgTextColor, 'background-color': msgBgColor}"
記法はどちらかに統一した方がよい。
属性値がオブジェクトリテラルなのでキャメル記法での記述が適切だと思われる。
スタイルの組み合わせをオブジェクトリテラルで指定
v-bind:styleの属性値がオブジェクトリテラルなので、属性をまとめたひとつのオブジェクトにしたテンプレート変数で参照することも可能。
const msgStyles = ref({ color: 'white', backgroundColor: 'black' })
v-bind:style="msgStyles"
複数のオブジェクトリテラルを配列で指定
スタイルが記述されたオブジェクトリテラルのプロパティを複数用意しておいて、それらをまとめてバインドする方法。
属性値の配列 [] として指定する。
const msgStyles = ref({ color: 'white', backgroundColor: 'black' })
const msgStyles2 = ref({ fontSize: '24pt' })
const msgStyles3 = ref({ color: 'pink', fontSize: '24pt' })
v-bind:style="[msgStyles, msgStyles2]"
v-bind:style="[msgStyles, msgStyles3]"
重複するスタイルプロパティがある場合、後ろにある方で上書きされる。
2.1.7 class 属性へのバインディング
スタイルシートのメンテナンス性を考えればスタイルクラス名を利用したclass属性へのバインディングの方が望ましいといえる。
この場合、v-bind:classを使う。
<script setup lang="ts">
import { ref, computed } from 'vue'
const msg = ref('こんにちは!世界')
const isTextColorRed = ref(true)
const isBgColorBlue = ref(false)
const styles = ref({ textColorRed: false, bgColorBlue: true })
const computedStyles = computed((): { textColorRed: boolean; bgColorBlue: boolean } => {
// textColorRed用
const randText = Math.round(Math.random())
let textColorFlg = true
if (randText == 0) {
textColorFlg = false
}
// bgColorBlue用
const randBg = Math.round(Math.random())
let bgColorFlg = true
if (randBg == 0) {
bgColorFlg = false
}
return {
textColorRed: textColorFlg,
bgColorBlue: bgColorFlg,
}
})
</script>
<template>
<p v-bind:class="{ textColorRed: true, bgColorBlue: true }">{{ msg }}</p>
<p v-bind:class="{ textColorRed: isTextColorRed, bgColorBlue: isBgColorBlue }">{{ msg }}</p>
<p v-bind:class="{ textColorPink: true }">{{ msg }}</p>
<p v-bind:class="{ 'text-color-pink': true }">{{ msg }}</p>
<p class="textSize24" v-bind:class="{ textColorRed: isTextColorRed, bgColorBlue: isBgColorBlue }">
{{ msg }}
</p>
<p class="textSize24" v-bind:class="styles">{{ msg }}</p>
<p v-bind:class="computedStyles">{{ msg }}</p>
</template>
<style>
.textColorRed {
color: red;
}
.text-color-pink {
color: pink;
}
.bgColorBlue {
background-color: blue;
}
.textSize24 {
font-size: 24px;
}
</style>
スタイルクラス適用をtrue/falseで指定
style属性へのバインドと同様にオブジェクトリテラルをv-bind:classの値として記述し、それぞれスタイル名をプロパティとする。
style属性との違いは、プロパティの値としてそれぞれのクラススタイルの適用の有無をtrue/falseで指定する点。
v-bind:class="{ textColorRed: true, bgColorBlue: true }"
v-bind:class="{スタイルクラス名: true/false, ・・・}"
true/falseの値をテンプレート変数として用意
v-bind:class="{ textColorRed: isTextColorRed, bgColorBlue: isBgColorBlue }"
スタイルクラス名がケバブ記法の場合
スタイルクラス名をシングルクォーテーションで囲む
v-bind:class="{ 'text-color-pink': true }"
.text-color-pink {
color: pink;
}
v-bind:class と class の併用
v-bind:class は通常の class属性と併用できる。
class="textSize24" v-bind:class="{ textColorRed: isTextColorRed, bgColorBlue: isBgColorBlue }"
オブジェクトリテラルで指定
v-bind:styleと同様にオブジェクトリテラルをそのままテンプレート変数として利用することができる。
const styles = ref({ textColorRed: false, bgColorBlue: true })
v-bind:class="styles"
算出プロパティを指定
v-bind:classの属性値としてスタイルクラスを適用するかどうかを示すtrue/false値は算出プロパティにすることもできる。
const computedStyles = computed((): { textColorRed: boolean; bgColorBlue: boolean } => {
// textColorRed用
const randText = Math.round(Math.random())
let textColorFlg = true
if (randText == 0) {
textColorFlg = false
}
// bgColorBlue用
const randBg = Math.round(Math.random())
let bgColorFlg = true
if (randBg == 0) {
bgColorFlg = false
}
return {
textColorRed: textColorFlg,
bgColorBlue: bgColorFlg,
}
})
v-bind:class="computedStyles"
算出プロパティを用意する関数の戻り値はオブジェクトリテラルである。
そのプロパティとしてスタイルクラス名を記述し、true/falseの値を変数で指定している。
オブジェクトの型指定
アロー式のシグネチャには次のコードが記述されている。
(): { textColorRed: boolean; bgColorBlue: boolean }
「:」(コロン)の右側はこの関数の戻り値の型を表す。
TyepScriptでは関数の戻り値のデータ型を指定でき、戻り値がオブジェクトの場合は、各プロパティ名とそのデータ型を次のように定義できる。
{ プロパティ名: データ型; ・・・}
2.2 イベントのディレクティブ
2.2.1 イベントリスナを設定するディレクティブ v-on
HTMLタグにイベントリスナを設定するには v-onディレクティブを使う。
<script setup lang="ts">
import { ref } from 'vue'
const randValue = ref('まだです')
const onButtonClick = (): void => {
const rand = Math.round(Math.random() * 10)
randValue.value = String(rand)
}
</script>
<template>
<section>
<button v-on:click="onButtonClick">クリック!</button>
<p>クリックの結果: {{ randValue }}</p>
</section>
</template>
v-on:イベント名="イベント発生時に実行するメソッド名"
const メソッド名 = (): void => {
処理内容
}
<button @click="onButtonClick">クリック!</button>
2.2.2 v-on のイベント
v-onディレクティブの引数として記述するイベント名にはJavaScriptで用意されているイベント名を記述する。
分類 | イベント名 | 発生タイミング |
---|---|---|
フォーカス | blur | フォーカスを失った時 |
focus | フォーカスを受けた時 | |
focusin | フォーカスを受けた時(親要素でもイベント検出可能) | |
focusout | フォーカスを失った時(親要素でもイベント検出可能) | |
マウス | click | クリックしたとき |
contextmenu | コンテキストメニューが表示されるとき | |
mousedown | マウスのボタンが押された時 | |
mouseenter | マウスポインタが要素に入った時(自要素のみ) | |
mouseleave | マウスポインタが要素を出た時(自要素のみ) | |
mousemove | マウスポインタが移動したとき | |
mouseout | マウスポインタが要素から出た時(子要素も含む) | |
mouseover | マウスポインタが要素に入った時(子要素も含む) | |
mouseup | マウスボタンが放された時 | |
wheel | マウスホイールが放された時 | |
入力 | change | ドロップダウンなどで入力内容が変更されたとき |
compositionend | IMEを使って入力を終了したとき | |
compositionstart | IMEを使って入力を開始したとき | |
compositionupdate | IMEを使って入力中 | |
input | 入力内容が更新されたとき | |
keydown | キーが押された時 | |
keypress | キーを押して文字が入力されたとき | |
keyup | キーが離された時 | |
select | テキストが選択された時 | |
その他 | resize | 要素サイズが変更されたとき |
scroll | スクロールされたとき |
2.2.3 メソッドの引数としてイベントオブジェクトを受け取る
v-onディレクティブに対応したイベントハンドラメソッドは、イベントオブジェクトを引数として受け取ることができる。
<script setup lang="ts">
import { ref } from 'vue'
const mousePointerX = ref(0)
const mousePointerY = ref(0)
const onImgMousemove = (event: MouseEvent): void => {
mousePointerX.value = event.offsetX
mousePointerY.value = event.offsetY
}
</script>
<template>
<section>
<img src="./assets/logo.svg" alt="Vueのロゴ" width="200" v-on:mousemove="onImgMousemove" />
<p>ポインタの位置: x={{ mousePointerX }}; y={{ mousePointerY }}</p>
</section>
</template>
メソッドの引数としてeventを用意し、イベントオブジェクトを受け取れるようにしている。
この例ではマウスイベントを利用するので引数の型にはMouseEventを指定している。
2.2.4 イベントオブジェクト以外を引数とするイベントハンドラメソッド
<script setup lang="ts">
import { ref } from 'vue'
const pBgColor = ref('white')
const onPClick = (bgColor: string): void => {
pBgColor.value = bgColor
}
</script>
<template>
<p v-on:click="onPClick('red')" v-bind:style="{ backgroundColor: pBgColor }">
ここをクリックすると背景色が変わります。
</p>
</template>
イベントハンドラメソッドではイベントオブジェクトだけでなく任意の引数を受け取れる。
引数は、テンプレートブロックで渡す。
上記では、イベントハンドラメソッドonPClickに引数(‘red’)を渡している。
2.2.5 イベントオブジェクトとその他の引数を併用するイベントハンドラメソッド
<script setup lang="ts">
import { ref } from 'vue'
const pMsg = ref('イベント前(ここをクリック!)')
const pBgColorEvent = ref('white')
const onPClickWithEvent = (bgColor: string, event: MouseEvent): void => {
pBgColorEvent.value = bgColor
pMsg.value = event.timeStamp.toString()
}
</script>
<template>
<p
v-on:click="onPClickWithEvent('green', $event)"
v-bind:style="{ backgroundColor: pBgColorEvent }"
>
{{ pMsg }}
</p>
</template>
イベントハンドラメソッドonPCLickWithEventはbgColorとeventの2つの引数が定義されている。
イベントを利用する部分のテンプレートは以下のようになっている。
v-on:click="onPClickWithEvent('green', $event)"
引数を省略した場合イベントオブジェクトは自動的に渡してくれるが、他の引数と組み合わせる場合は引数部分で$eventを明記する必要がある。
引数の順番は任意だが定義部分とテンプレート側の呼び出し部分で順番を揃える必要がある。
2.2.6 v-on の修飾子(Modifiers)
修飾子とはv-onディレクティブの引数の後に「.」(ドット)でつないで記述するキーワード。
修飾子 | 内容 |
---|---|
stop | イベントのバブリングをキャンセルする (event.stopPropagation()に同じ) |
capture | イベントリスナをキャプチャモードに設定する |
self | イベントがこの要素で発生した場合のみイベントを実行する |
prevent | イベントが規定の処理をキャンセルする (event.preventDefault()に同じ) |
passive | 該当イベントのデフォルトの挙動が即実行される |
once | イベントの実行を1回のみとする |
DOMイベントのフェーズ(Event Phase)
イベントフェーズとはイベントの伝達のこと。
イベントが発生すると以下の段階(Phase)で伝達される。
- キャプチャーフェーズ(Capture Phase)
イベントがルート要素からターゲット要素まで下りていく - ターゲットフェーズ(Target Phase)
イベントがターゲット要素に到達する - バブリングフェーズ(Bubbling Phase)
イベントがルート要素までさかのぼる
次々と要素をたどりながらその要素に設定されているイベントハンドラを実行していくのがイベントの伝播である。
ただし、JavaScriptでDOMイベントを設定する場合、デフォルトの設定はバブリングフェーズとなっている。キャプチャーフェーズでも実行されるようにするにはオプションを設定する必要がある。
そのため、DOMイベントハンドラの実行は通常バブリングフェーズで起こるといえる。
stop と capture と self 修飾子
.stop は、バブリングをキャンセルして、バブリングフェーズで親要素に設定されたイベントハンドラの実行を阻止する。
.capture は、キャプチャフェーズで該当のイベントハンドラを実行し、代わりにバブリングフェーズではイベントハンドラを実行しないように設定する。
.self は、その要素自体がイベントの発生源のときのみイベントハンドラを実行するように設定する。
prevent 修飾子
<script setup lang="ts">
import { ref } from 'vue'
const msg = ref('未送信')
const onFormSubmit = (): void => {
msg.value = '送信されました。'
}
</script>
<template>
<form action="#" v-on:submit.prevent="onFormSubmit">
<input type="text" required />
<button type="submit">送信</button>
</form>
<p>{{ msg }}</p>
</template>
上記は、ボタンをクリックした時に「送信されました」と表示するだけのプログラムで、入力チェックにHTMLのフォームバリデーションを利用している。
HTMLのフォームバリデーションを有効にするには、入力コントロールを from タグで囲み、ボタンの type を submit にする必要がある。
この場合のイベント設定は v-on:submit を利用して記述する。
だたし、v-on:submit だけだと onFormSubmit メソッドが実行された直後に、本来のサブミットイベント(button type=”submit”)も実行されて from action=”#” が呼び出されてしまう。
この本来のイベントをキャンセルするのが .prevent 修飾子である。
このprevent 修飾子は内部で該当イベントオブジェクトに対してJavaScript標準のpreeventDefault()メソッドを呼び出すことで実現されている。
HTMLのフォームバリデーション
フォームバリデーションとは、ユーザーがフォームに入力した値が正しいかどうかチェックすること。
passive 修飾子
この修飾子はイベント処理関数内でpreeventDefault()メソッドを実行していないことをブラウザに通知するもので、.prevent 修飾子の逆の働きともいえる修飾子である。
.passive を付けることによりブラウザが即座にイベント処理を行えるようになる。
.passive を scroll イベントに適用すると、スクロール処理が即座に実行されるようになり、モバイル環境でのスクロールのカクツキを軽減できる。
2.2.7 クリックイベントとキーイベントの修飾子
v-on ディレクティブの引数のうち、クリックイベントとキーイベントには専用の修飾子が用意されている。
<script setup lang="ts">
import { ref } from 'vue'
const msg = ref('まだです!')
const onEnterKey = (): void => {
msg.value = 'エンターキーが押下されました。'
}
const OnRightButtonClick = (): void => {
msg.value = 'ボタンが右クリックされました。'
}
const onShiftclick = (): void => {
msg.value = 'シフトを押しながらクリックされました。'
}
</script>
<template>
<p>{{ msg }}</p>
<input type="text" v-on:keydown.enter="onEnterKey" /><br />
<button v-on:click.right="OnRightButtonClick">右クリック</button><br />
<button v-on:click.shift="onShiftclick">シフトを押しながらクリック</button><br />
</template>
キーイベントの修飾子
keydown を始め keypress、keyup といったキーイベントには押されたキーに対応する修飾子をさらに付与できる。…
v-on:keydown.q="・・・"
アルファベットでないキーの修飾子、キーエイリアス。
修飾子 | 対応キー |
---|---|
enter | [Enter] |
tab | [Tab] |
delete | [Delete]または[Backspace] |
esc | [Esc] |
space | [Space] |
up | [↑] |
down | [↓] |
left | [←] |
rignt | [→] |
click イベントの修飾子
v-on:clickの修飾子
修飾子 | 対応ボタン |
---|---|
left | 左ボタン |
right | 右ボタン |
middle | 中ボタン |
システム修飾子
v-on:click.shift はシステム修飾子と呼ばれる修飾子。
修飾子 | 対応キー |
---|---|
ctrl | [Ctrl] |
alt | [Alt] |
shift | [Shift] |
meta | macOSでは[]、Windowsでは[] |
ecact 修飾子
.enter 修飾子は[Enter]キーを単独で押下したときだけでなく[Shift]+[Enter]キーなど他のキーとの組み合わせでもイベントが発生してしまう。
[Enter]キーが単独で押されたときのみに限定したい場合は .exact 修飾子を併用する。
v-on:keydown.enter.exact="onEnterKey"
コメント