今日は、Vue3で画面に値を表示する方法と、HTMLの属性・クリック操作をJavaScriptにつなぐ書き方を触ったので、そのメモです。
画像解析の結果をブラウザで表示することを考えると、画面を値に合わせて変えたり、ボタン操作を受け取ったりする部分は早めに理解しておきたいと思いました。
まだ途中段階なので、勘違いなどあれば教えていただけるとうれしいです。
今日やったこと
今日は、テンプレート構文での値の表示、v-bindでの属性設定、v-onでのクリック処理を確認しました。
Vueコンポーネントの<template>に書くものは、厳密にはただのHTMLではなく、Vueのテンプレート構文です。HTMLをベースに、画面とJavaScriptの値・処理を結びつけるためのVue独自の記法が追加されています。
VueはテンプレートをJavaScriptへコンパイルし、値が変わったときに必要なDOMを更新します。今の自分は、テンプレートを「画面をどう表示したいか書く場所」と受け取っています。 vueframework
まず、二重波括弧の{{ }}を使って値を表示しました。<script setup>のトップレベルで定義した値は、テンプレートから参照できます。
<script setup>
// refは、画面の表示と連動させたい値を作るために使う
import { ref } from 'vue'
// 数値をリアクティブな値として定義する
// JavaScript側で値を変更するときは、count1.valueのように.valueを使う
const count1 = ref(2)
const count2 = ref(4)
</script>
<template>
<!-- count1とcount2を足した結果を画面に表示する -->
<div>{{ count1 + count2 }}</div>
<!-- 三項演算子を使った条件分岐 -->
<!-- count1がcount2より大きければYes、そうでなければNoを表示する -->
<div>{{ count1 > count2 ? 'Yes' : 'No' }}</div>
</template>
{{ }}の中には、JavaScriptの単一の式を書けます。計算式や三項演算子は書けますが、if文のような複数の文を書く場所ではありません。 vueframework
|
HTMLの中にJavaScriptを書いているように見えるけれど、書けるものにはちゃんとルールがあるんですね。 |
今のところは、{{ }}を「変数の値や、値から計算した結果を画面に出す場所」と考えると分かりやすそうです。
次に、v-から始まるディレクティブを確認しました。ディレクティブはVueが用意している特別な属性で、値の変化に合わせて画面へ処理を適用するために使います。 vueframework
<script setup>
import { ref } from 'vue'
// 画面に表示する値を定義する
const count = ref(2)
</script>
<template>
<!-- マスタッシュ構文でcountの値を表示する -->
<div>{{ count }}</div>
<!-- v-textでも、要素のテキストとしてcountの値を表示できる -->
<!-- この例では、上の{{ count }}とほぼ同じ表示結果になる -->
<div v-text="count"></div>
</template>
v-textは、要素のテキストとして値を表示します。単純に文字を出す場合は{{ }}のほうをよく見かける気がするので、まずは両方の存在を知っておこうと思います。
v-htmlを使うと、文字列をHTMLとして解釈して表示できます。
<script setup>
import { ref } from 'vue'
// HTMLタグを含んだ文字列を定義する
const message = ref('<h1>Hello Vue3!</h1>')
</script>
<template>
<!-- {{ }}では、<h1>も文字列の一部として表示される -->
<div>{{ message }}</div>
<!-- v-htmlでは、messageの文字列をHTMLとして解釈して表示する -->
<div v-html="message"></div>
</template>
{{ message }}では<h1>も文字列として表示されます。一方でv-htmlでは、<h1>が見出しとして表示されます。 vueframework
|
見出しを出せて便利そうですが、受け取った文字列をそのまま表示するのは少し怖そうです。 |
v-htmlは信頼できる内容にだけ使う必要があります。ユーザー入力などをそのまま表示すると、XSS(クロスサイトスクリプティング)につながる危険があるためです。 vueframework
つまずいたところ
{{ }}で表示する場所と、v-bindで属性に値を設定する場所の使い分けで少し止まりました。
最初は、リンク先のhrefに変数を設定するときも{{ }}が使えると思っていました。
<script setup>
import { ref } from 'vue'
// リンク先のURLを定義する
const vueURL = ref('https://vuejs.org')
</script>
<template>
<!-- この書き方はできない -->
<!-- HTML属性の中では{{ }}を使えない -->
<a :href="{{ vueURL }}">Vue.js</a>
</template>
HTML属性の中ではマスタッシュ構文は使えないため、属性に値を設定するときはv-bindを使います。 vueframework
<script setup>
import { ref } from 'vue'
// リンク先のURLを定義する
const vueURL = ref('https://vuejs.org')
// a要素に設定するid属性の値を定義する
const vueID = ref('vue-link')
</script>
<template>
<!-- v-bind:idでid属性へvueIDの値を設定する -->
<!-- v-bind:hrefでhref属性へvueURLの値を設定する -->
<a v-bind:id="vueID" v-bind:href="vueURL">
Vue.js
</a>
<!-- v-bind:は:へ省略できる -->
<!-- 上のa要素と同じ意味 -->
<a :id="vueID" :href="vueURL">
Vue.js
</a>
</template>
v-bind:は:へ省略できます。v-bindを使うと、idやhrefなどのHTML属性をVueの値と結びつけられます。 vueframework
|
画面に文字を出すなら |
複数の属性をまとめて設定する書き方と、disabledのようなブーリアン属性も試しました。
<script setup>
import { ref } from 'vue'
// リンクに設定したい値を定義する
const vueURL = ref('https://vuejs.org')
const vueID = ref('vue-link')
// ボタンを無効化するかどうかを管理する
const isDisabled = ref(true)
</script>
<template>
<!-- オブジェクトの形で、idとhrefをまとめて設定する -->
<!-- idにはvueID、hrefにはvueURLが設定される -->
<a v-bind="{ id: vueID, href: vueURL }">
Vue.js
</a>
<!-- disabledはブーリアン属性 -->
<!-- isDisabledがtrueならボタンは押せず、falseなら押せる -->
<button :disabled="isDisabled">
Disabled Button
</button>
</template>
ブーリアン属性は、バインドした値が真値なら属性が付与され、偽値なら取り除かれます。また、通常の属性ではnullまたはundefinedを渡すと、対象の属性が要素から除外されます。 vueframework
もう一つ止まったのは、クリックイベントでイベントオブジェクトを受け取る書き方です。
v-onは、クリックなどのDOMイベントが起きたときにJavaScriptを実行するディレクティブです。v-on:clickは@clickと省略して書けます。
<script setup>
import { ref } from 'vue'
// クリック回数を管理する。最初の値は0
const count = ref(0)
</script>
<template>
<!-- @clickはv-on:clickの省略形 -->
<!-- クリックするたびにcountを1増やす -->
<button @click="count++">
<!-- 現在のcountを画面に表示する -->
Count is: {{ count }}
</button>
</template>
@click="count++"のように処理を直接書く方法は、インラインハンドラと呼ばれます。
関数を用意して、その関数名を指定する書き方も試しました。
<script setup>
import { ref } from 'vue'
// クリック回数を管理する
const count = ref(0)
// ボタンがクリックされたときに実行する関数
function increment() {
// JavaScript側でrefの中身を変えるため、.valueを付ける
count.value++
}
</script>
<template>
<!-- クリック時にincrement関数を実行する -->
<button @click="increment">
1増やす
</button>
<!-- 関数で更新されたcountを画面へ表示する -->
<p>Count is: {{ count }}</p>
</template>
関数名を指定する書き方はメソッドハンドラです。処理が長くなりそうな場合は、関数に分けたほうが読みやすそうです。
メソッドハンドラでは、イベントが起きたときの情報を持つイベントオブジェクトが、関数の第一引数に自動的に渡されます。
<script setup>
import { ref } from 'vue'
// クリックした位置のX座標を表示するための値
const count = ref(0)
// clickイベントが起きると、Vueがeventを渡してこの関数を呼び出す
function increment(event) {
// eventには、クリックした要素やクリック座標などの情報が入っている
console.log(event)
// clientXは、ブラウザ画面の左端からクリック位置までのX座標
// refの値を変更するため、.valueを使う
count.value = event.clientX
}
</script>
<template>
<!-- 現在保存されているX座標を表示する -->
<p>{{ count }}</p>
<!-- click時にincrementを実行する -->
<!-- eventは自動的にincrementの第一引数へ渡される -->
<button @click="increment">
クリックしたX座標を表示
</button>
</template>
|
|
インラインハンドラでイベントオブジェクトを使う場合は、特殊な変数である$eventを使います。
<script setup>
import { ref } from 'vue'
// クリックした位置のX座標を保存する
const count = ref(0)
</script>
<template>
<!-- インラインハンドラ内では、$eventでイベントオブジェクトを参照できる -->
<!-- $event.clientXはクリック位置のX座標 -->
<button @click="count = $event.clientX">
クリックしたX座標: {{ count }}
</button>
</template>
独自の引数も渡したい場合は、関数を呼び出す形で$eventを明示的に渡します。
<script setup>
import { ref } from 'vue'
// 計算結果を表示する値
const count = ref(0)
// eventにはクリック情報、valueには自分で指定する数値が入る
function increment(event, value) {
// クリック位置のX座標にvalueを掛けた結果を保存する
count.value = event.clientX * value
}
</script>
<template>
<!-- 現在の計算結果を表示する -->
<p>{{ count }}</p>
<!-- $eventでイベントオブジェクト、5で独自の引数を渡す -->
<button @click="increment($event, 5)">
X座標を5倍して表示
</button>
</template>
今の理解(メモ)
まだふわっとしていますが、Vueのテンプレート構文は、画面とJavaScriptの値・処理を結びつけるための書き方だと思っています。
-
{{ }}は、テンプレート内に値や式の結果を表示するために使う -
v-から始まるディレクティブは、Vueの機能を属性のような形で指定するもの -
v-textは値をテキストとして表示する -
v-htmlは文字列をHTMLとして表示する。ただし、信頼できる値以外には使わない -
v-bindは、hrefやid、disabledなどのHTML属性へVueの値を設定するために使う -
v-bindは:に省略できる -
v-onは、クリックなどのイベントが起きたときに処理を実行するために使う -
v-onは@に省略できる -
@click="count++"はインラインハンドラ、@click="increment"はメソッドハンドラ - メソッドハンドラではイベントオブジェクトが第一引数に入り、インラインハンドラでは
$eventで参照する
|
表示する値、属性に渡す値、クリック時に動かす処理が、テンプレートの中でつながっているように見えてきました。 |
次にやりたいこと
次は、イベント修飾子とフォーム入力を実際に使い、ユーザー操作によって画面が変わる流れを確かめたいです。
- イベント修飾子の
.stopを親要素と子要素のクリックイベントで試す。子要素をクリックしたときに親要素の処理がどう変わるか確認したいです -
.preventをフォームで試す。画面遷移を止めた状態で、入力した値をJavaScriptで扱う流れを見てみたいです -
.onceを使う。一度だけ実行するボタンを作り、どんな用途で便利なのか考えたいです -
v-modelを触る。入力欄の内容とrefの値がどう連動するのか確認したいです - 小さな入力フォームを作る。値の表示、属性の設定、クリックイベントを一つの画面にまとめてみたいです
おわりに
今回は、{{ }}、v-bind、v-onがそれぞれ別の役割を持っていることを整理できました。特に「表示するなら{{ }}」「属性なら:」「イベントなら@」という見方ができるようになり、テンプレートを読むときの迷いが少し減った気がします。
学習中の内容なので、勘違いや理解不足もあると思います。もし気になる点があれば教えてもらえるとうれしいです。フロント側の書き方を覚えることで、今後は画像解析の結果をブラウザに表示するだけでなく、条件を切り替えたり、結果を操作したりできる画面につなげていきたいです。
今回のリファレンス
最後に、自分があとで見返せるよう、今回出てきた記法を簡単にまとめておきます。
| 書き方 | 役割 | 例 |
|---|---|---|
{{ 式 }} |
値や計算結果をテキストとして表示する | {{ count + 1 }} |
v-text="値" |
値を要素のテキストとして表示する | <p v-text="message"></p> |
v-html="値" |
文字列をHTMLとして表示する。信頼できる値だけに使う | <div v-html="html"></div> |
v-bind:属性名="値" |
HTML属性へ動的に値を設定する | <a v-bind:href="url"> |
:属性名="値" |
v-bind:の省略形 |
<a :href="url"> |
v-on:イベント名="処理" |
イベント発生時に処理を実行する | <button v-on:click="count++"> |
@イベント名="処理" |
v-on:の省略形 |
<button @click="count++"> |
@click="count++" |
短い処理を直接書くインラインハンドラ | @click="count++" |
@click="increment" |
定義済み関数を呼ぶメソッドハンドラ | @click="increment" |
$event |
インラインハンドラでイベントオブジェクトを参照する | @click="save($event)" |
ref(初期値) |
画面の表示と連動する値を作る | const count = ref(0) |
値.value |
JavaScript側でrefの値を読み書きする |
count.value++ |
テンプレートではrefの.valueを省略して書けますが、<script setup>内のJavaScriptで値を変更するときは.valueが必要です。ここはまだ間違えやすいので、実際に書きながら覚えていきたいです。 vueframework
注意事項
本ブログに掲載している内容は、私個人の見解であり、
所属する組織の立場や戦略、意見を代表するものではありません。
あくまでエンジニアとしての経験や考えを発信していますのでご了承ください。

