テンプレート構文について
- このHTMLはそのままブラウザにHTMLとして渡されるわけではない
- 「.vue」の中身はViteなどによってJavascriptのコードに変換される
- HTMLのコードをjavascriptに変換してくれている
- テンプレート構文がHTMLのルールに従ってくれている
二重波括弧でデータを描画
<script setup></script>
<template>
<div>{{ 3 + 4 }}</div>
</template>
- 二重波括弧の中にはjavascriptの式を書くことができる
- 二重波括弧の中に「3+4」と書くと画面には「7」が表示される
scriptの中で定義した定数、関数も使える
<script setup>
import { ref } from 'vue'
const count = ref(2)
</script>
<template>
<div>{{ count + 3 }}</div>
</template>
- 定義した定数countの値も反映される
<script setup>
import { ref } from 'vue'
const count = ref(2)
</script>
<template>
<div>{{ count > 3 ? 'Yes' : 'No' }}</div>
</template>
- 三項演算子も書ける
【注意点】
二重波括弧の中には単一の式だけ書ける
- 1つの式だけ書ける
- if文は書けない
二重波括弧内でscriptで定義された定数、関数などを使う場合は、そのデータがscript内でトップレベルで定義されている必要がある
- トップレベルとは?
→if文の中、関数の中などに入っていない、ということ - if文の中、関数の中で定義された関数はtemplateでは使えない
ディレクティブについて
htmlディレクティブ
<script setup>
import { ref } from 'vue'
const message = ref('<h1>Hello</h1>')
</script>
<template>
<div>{{ message }}</div>
</template>
- これはHelloがタグ含めて文字列として表示されてしまう
<script setup>
import { ref } from 'vue'
const message = ref('<h1>Hello</h1>')
</script>
<template>
<div v-html="message"></div>
</template>
-
<div v-html="message"></div>
とすることでタグが反映される! - 便利だがセキュリティ上の問題があったりする
- ユーザーからもらった値ではない信頼できるデータのみ使用する必要がある
- ウェブページが自由に書き換えられてしまうため
v-bindディレクティブ
<script setup>
import { ref } from 'vue'
const vueURL = ref('https://vuejs.org')
</script>
<template>
<a href="{{ vueURL }}">Vue.js</a>
</template>
- このURL指定方法だとリンクできない。押しても飛ばない。
- 二重波括弧は属性の値では使用できない
<script setup>
import { ref } from 'vue'
const vueURL = ref('https://vuejs.org')
</script>
<template>
<a v-bind:href="vueURL">Vue.js</a>
</template>
<a v-bind:href="vueURL">Vue.js</a>
- こうするとリンクが設定できる
href属性に限った話ではない!
<script setup>
import { ref } from 'vue'
const vueURL = ref('https://vuejs.org')
const vueId = ref('vue-link')
</script>
<template>
<a v-bind:id="vueId" v-bind:href="vueURL">Vue.js</a>
</template>
- idにも動的に値を設定できる
- どうな属性にもv-bindで値を設定できる
- 普通の値には二重波括弧を使う、属性値にはv-bindを使う
- v-bindディレクティブを非常に頻繁に利用される
v-bindは省略記法あり
<a :id="vueId" :href="vueURL">Vue.js</a>
-
:
のみで記述できる(v-bindは省ける) - eslintの設定では省略記法が推奨されており、保存するだけで省略される(されなかったけど)
属性名と属性値の変数や定数が同じ名前の場合は「=以降」を省略して書くこともできる
<script setup>
import { ref } from 'vue'
const id = ref('vue-link')
</script>
<template>
<a :id>Vue.js</a>
</template>
<a :id>Vue.js</a>
<a :id="id">Vue.js</a>
- こちらが同じ状態ということ!
- 属性名→「id」、属性名の定数→「id」の状態
undefinedとnullを入れるとその属性が存在しなくなる
<script setup>
import { ref } from 'vue'
const vueURL = ref('https://vuejs.org')
const vueId = ref('vue-link')
</script>
<template>
<a :id="undefined" :href="null">Vue.js</a>
</template>
- idもhrefも消えている状態
Boolean属性について
- undefined、null以外にも「false」と入れるとその属性が消えるような属性もある
- どんな属性なのか?
→Boolean属性
Boolean属性とは
- HTMLの話
- 値をとらなくてもいい属性
<buttom disabled>ボタン</button>
- ボタンタグにおけるdisabled属性など
Boolean属性に対してv-bindを使った場合、、
<buttom :disabled="null">ボタン</button>
<buttom :disabled="undefined">ボタン</button>
- nullやundefinedを指定した時には消える
<buttom :disabled="false">ボタン</button>
- falseを指定した時も消える
- 「0」「-0」「0n」「NaN」を入れても消える
- vue.jsが対応しているBoolean属性の一覧がある
v-bindで一度に複数の属性を指定する方法
<script setup>
import { ref } from 'vue'
const vueURL = ref('https://vuejs.org')
const vueId = ref('vue-link')
</script>
<template>
<a :id="vueId" :href="vueURL">Vue.js</a>
</template>
- それぞれに属性を指定している状態
<script setup>
import { ref } from 'vue'
const vueURL = ref('https://vuejs.org')
const vueId = ref('vue-link')
</script>
<template>
<a v-bind="{ id: vueId, href: vueURL }">Vue.js</a>
</template>
- このように書くとひとまとめにすることができる!
v-onディレクティブ
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<button v-on:click="count++">button</button>
</template>
- v-onの中に
count++
という処理を記述する - clickイベント発生のたびに
count++
の処理が動く - ボタンを押すと数字が1つずつ増える
v-onも省略できる
<button @click="count++">button</button>
-
v-on:click
→@click
に省略できる - こちらも省略が推奨されている
関数の指定でも実行できる
<script setup>
import { ref } from 'vue'
const count = ref(0)
function countUp() {
count.value++
}
</script>
<template>
<p>{{ count }}</p>
<button @click="countUp">button</button>
</template>
-
@click
に直接処理を書くのではなく、関数を指定する形 -
こちらでも同様の処理ができる
-
clickなどの実行→イベント
-
イベントの中身→ハンドラ
-
vue.jsには処理を直接各パターン、関数を書くパターンの2つのパターンのハンドラがある
-
直接書くハンドラ→インラインハンドラ
-
関数を書くハンドラ→メソッドハンドラ
clickイベント以外にどんなイベントを指定できる?
- ドキュメントに書かれている
- いっぱいある
イベントオブジェクト
- イベントオブジェクトの取得方法
- clickイベントのようなブラウザが発生させているイベントはそのイベントが発生した時に、同時にイベントオブジェクトというそのイベントの情報を持ったオブジェクトを生成している
- vue.jsはそれを取得できるようになっている
function countUp(event) {
console.log(event)
count.value++
}
- 第一引数に指定するだけで、ボタンをクリックするとオブジェクトが表示される
- イベントの情報を持ったイベントオブジェクト
- 例えばclientX、clienYはボタンがクリックされた時のマウスの縦軸・横軸のポジション
<script setup>
import { ref } from 'vue'
const count = ref(0)
function countUp(event) {
count.value = event.clientX
}
</script>
<template>
<p>{{ count }}</p>
<button @click="countUp">button</button>
</template>
- こうするとボタンを押した時のマウスの位置を表示することができる
インラインハンドラ(直接書くハンドラ)はどのようにイベントオブジェクトにアクセスするのか
<script setup>
import { ref } from 'vue'
const count = ref(0)
function countUp(event) {
count.value = event.clientX
}
</script>
<template>
<p>{{ count }}</p>
<button @click="count = $event.clientX">button</button>
</template>
- インラインハンドラでは
$event
という特殊な変数を使うことができる -
4event
にイベントオブジェクトが格納されている - 上記で同じような動きが実装できる
v-onでハンドラに引数を渡す
- メソッドハンドラとして設定した関数に引数を渡したい場合
- メソッドハンドラとして呼び出すのではなく、インラインハンドラとして関数呼び出し式を記述する
<script setup>
import { ref } from 'vue'
const count = ref(0)
function countUp(event, times) {
count.value = event.clientX * times
}
</script>
<template>
<p>{{ count }}</p>
<button @click="countUp($event, 5)">button</button>
</template>
<button @click="countUp($event, 5)">button</button>
- このようにインラインハンドラとして記述する(
$event
を利用すること) - クリック位置×5の数値を表示している
イベント修飾子
preventDefalult
- デフォルトの挙動を防ぐ
<script setup>
import { ref } from 'vue'
const count = ref(0)
function countUp(event, times) {
count.value = event.clientX * times
}
</script>
<template>
<a href="https://vuejs.org" @click="$event.preventDefault()">Vue.js</a>
</template>
- クリックしてもデフォルトの挙動が動かなくされているのでリンクしない
stopPropagation
- 伝播を止める
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<div @click="count++">
<button>button</button>
</div>
</template>
- これはボタン押すと通常通り数字増える
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<div @click="count++">
<button @click="$event.stopPropagation()">button</button>
</div>
</template>
- これは増えない、ボタンが動作しなくなる
- 親の要素にクリックイベントが発生したことを伝えない(伝播させない)という処理になっている
vue.jsではpreventDefaultとstopPropagationをよく使うので、簡単に実行できるシステムを持っている
→これがイベント修飾子
prevent
<script setup>
import { ref } from 'vue'
const count = ref(0)
function countUp(event, times) {
count.value = event.clientX * times
}
</script>
<template>
<a href="https://vuejs.org" @click="$event.preventDefault()">Vue.js</a>
</template>
↓↓↓↓
<script setup>
import { ref } from 'vue'
const count = ref(0)
function countUp(event, times) {
count.value = event.clientX * times
}
</script>
<template>
<a href="https://vuejs.org" @click.prevent="">Vue.js</a>
</template>
<a href="https://vuejs.org" @click="$event.preventDefault()">Vue.js</a>
<a href="https://vuejs.org" @click.prevent="">Vue.js</a>
- このように書き換えるだけで同じ記述になる
<a href="https://vuejs.org" @click.prevent>Vue.js</a>
- ↑これでも問題なし
stop
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<div @click="count++">
<button @click="$event.stopPropagation()">button</button>
</div>
</template>
↓↓↓↓
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<div @click="count++">
<button @click="$event.stop="">button</button>
</div>
</template>
<button @click="$event.stopPropagation()">button</button>
<button @click="$event.stop="">button</button>
- このように書き換えるだけで同じ記述になる
<button @click="$event.stop>button</button>
- ↑これでも問題なし
stopや、preventを実行した上でなにか処理を追加することもできる
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<div @click="count++">
<button @click="$event.stop="count = 30">button</button>
</div>
</template>
- 追加でインラインハンドラ、イベントハンドラを追加することもできる
- ボタンを押すと30に数値が変更する(カウントアップの処理は動かないまま)
両方使うこともできる
<a href="https://vuejs.org" @click.prevent.stop>Vue.js</a>
- 両方も使える
キー修飾子
- イベント修飾子に似たもの、キーボード系のイベントのみに使える
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<input type="text" @keyup="count++" />
</template>
keyup
- ↑キーボードを押して離した時に発生するイベント
- 文字を入力するとカウントが増える
すべてのキーボードではなく、特定のキーボードのみに反映させたい
→キー修飾子
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<input type="text" @keyup.space="count++" />
</template>
-
@keyup.space="count++"
とするとスペースを押した時だけカウントが反映される
複数組み合わせも可能
vue.js
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
<input type="text" @keyup.space.delete="count++" />
</template>
<input type="text" @keyup.space.delete="count++" />
- スペースを押した時と、デリートを押した時に反映される状態
ディレクティブの構造
- 角括弧を使ってディレクティブの引数にscriptのデータを指定できる
- 解説見たがよくわからなかった
v-model
<script setup>
import { ref } from 'vue'
const userInput = ref('')
</script>
<template>
<p>{{ userInput }}</p>
<input v-model="userInput" type="text" />
</template>
- inputタグのようにユーザーから入力されたデータはスクリプトタグの中でも使いたい
- スクリプトのデータと入力欄を常に同じ値にする
→そのような時に利用するのがv-model - v-modelを設定するだけで、inputタグと
const userInput = ref('')
の値は常に同じ値になる
<script setup>
import { ref } from 'vue'
const userInput = ref('')
</script>
<template>
<p>{{ userInput }}</p>
<input v-model="userInput" type="text" />
<button @click="userInput = 'hi'">button</button>
</template>
- ボタン押すとどちらも「hi」に変わる
computed
- リアクティブシステムを守ったまま、処理を1つにまとめる方法
<script setup>
import { ref } from 'vue'
const score = ref(0)
</script>
<template>
<p>{{ score > 3 ? 'Good' : 'Bad' }}</p>
<p>{{ score }}</p>
<button @click="score++">+1</button>
</template>
- ボタンを押すと数値が増えて、判定によってBAd、Goodを表示する処理を作った
<script setup>
import { ref } from 'vue'
const score = ref(0)
const evaluation = score.value > 3 ? 'Good' : 'Bad'
</script>
<template>
<p>{{ evaluation }}</p>
<p>{{ score }}</p>
<button @click="score++">+1</button>
</template>
- これは上のものと同じ式なのか→違う!
<p>{{ score > 3 ? 'Good' : 'Bad' }}</p>
-
{{ evaluation }}
- この2つは同じ処理なのか→違う!
const evaluation = score.value > 3 ? 'Good' : 'Bad'
- ここの
evaluation
に入る値は何なのか? -
score.value > 3 ? 'Good' : 'Bad'
この式が評価された値が入る - この式が評価された値とは?
- const score = ref(0)→つまり0が入る
- つまり
Bad
が常にconst evaluationに入る状態
- なので数値を増やしてもずっとBadが表示
<script setup>
import { ref } from 'vue'
const score = ref(0)
const evaluation = ref(score.value > 3 ? 'Good' : 'Bad')
</script>
<template>
<p>{{ evaluation }}</p>
<p>{{ score }}</p>
<button @click="score++">+1</button>
</template>
const evaluation = ref(score.value > 3 ? 'Good' : 'Bad')
- ここをrefで包めばいいのでは?→違う
- refの関数の中にBadという文字列を入れているだけなので同じ
↑説明の意味はさっぱりわからないがとにかく無理だということ
リアクティブシステムを保ったまま式をまとめたい(上記はまとめられていない状態ということ)
その時に使用するのがcomputed
import { ref, computed } from 'vue'
- refやリアクティブと同様にインポートして使用する
const evaluation = computed(() => {
score.value > 3 ? 'Good' : 'Bad'
})
- refやリアクティブと同様に関数として呼び出す
- computedは引数に関数を入れる必要がある
- 関数の中でまとめたい処理を記述する
const evaluation = computed(() => {
score.value > 3 ? 'Good' : 'Bad'
})
console.log(evaluation)
- console.logでevaluationの中身を見てみる
- refオブジェクトのように複雑なオブジェクトを返している
- ほとんどrefオブジェクトと同じ(computed refオブジェクトと呼ぶ)
- スクリプトやテンプレートでまるでrefオブジェクトのように使用できる
console.log(evaluation.value)
- このようにもできる
- こうするとなにが返ってくるのか?
-
.value
に最初にアクセスした時に、computedに渡した引数が実行される
その返り値が.value
の中に格納される
const evaluation = computed(() => {
return score.value > 3 ? 'Good' : 'Bad'
})
console.log(evaluation.value)
- 返り値が無かったのでいったんreturnで返してあげると、
Bad
が表示される - computedの関数の中では必ずreturnをする必要がある
- returnが無いとeslintの設定でエラーも出る
- computedが内部的に色んな処理を実行しているので、ボタンを押すとBadがGoodに変化するようになっている
- computedを使って引数に関数を入れてreturnでまとめた処理を返せばいい感じに処理を一つにまとめることができる
- 処理をひとつにまとめる、の意味がいまいちよくわからない
- computedの内部処理の解説も意味がわからなかった
computedを使う時はここに注意する
- いったん割愛
- 後にまとめる