Vue3 & Nuxt3 やってみる
目的
- お仕事で Vue を使っているので基本的な構文などを理解して、基礎的なコードなら書ける・読めるようになる
- 将来的に応用が効くような基礎部分を固める
Vue3 のチュートリアル
まず、以下をやってみる
Step1
- tutorial が終わったら Guide を読めって言っている
- Options API と Composition API の 2 つの API styles が存在する
-
https://vuejs.org/guide/introduction.html#api-styles
- Options API
-
data
,methods
,mounted
といったオプションオブジェクトを使ってコンポーネントのロジックを定義する - オプションで定義されたプロパティは functions の中で
this
を使って公開される
-
- Composition API
- インポートされた API functions を使ってコンポーネントのロジックを定義する
- SFC では
<script setup>
で使用される - setup 属性はコンパイル時の変換のヒントになっている
- Options API
-
https://vuejs.org/guide/introduction.html#api-styles
- SFC mode と HTML mode がある
- SFC(Single File Component)
- Vue を使ってる開発者のほとんどがこれらしい
-
.vue
ファイルの中に HTML, CSS, JavaScriot が全部入ってる
-
- tutorial上で切り替えられる
- ★ ひとまず、Options API, SFC で行く
- ★ ひとまず、Options API, SFC で行く
Step2
- declarative rendering: Vue の core feature
- 宣言的レンダリング(?)
- HTMLを拡張したテンプレートシンタックス
- JS の state に合わせてHTMLが自動的に更新される
- リアクティブな state はコンポーネントに保持される
- リアクティブ
- ★ 状態の変化を自動的に伝播する仕組みのことだと思う
- リアクティブ
-
data
を使ってリアクティブな state を宣言できる-
data
は オブジェクトを返す関数 -
data
内で定義したオブジェクトはHTML内の{{ }}
で表示できる- ★ mustaches syntax というらしい
- この中は任意の JS 表現を使える
- ★ これ、内容によるけど HTML 内でやるのか、data 内でやるのかは考える必要がありそう
-
- 宣言的レンダリング(?)
Step3
-
v-bind
- 属性をダイナミックな値に紐付ける
-
v-
から始まるものは Vueのテンプレートシンタックス、ディレクティブというっぽい -
data
のプロパティを入れたりできる - titleClass って CSS の class があるとして、
v-bind:class="titleClass
で紐付けれる-
:class="titleClass"
って省略形もあるっぽい
-
Step4
-
v-on
で DOM イベントを listen できる-
v-on:click="increment"
-
@click="increment"
とも書ける
-
- click したときの increment は methods 内で定義する
-
Step5
-
v-bind
とv-on
で双方向バインディングができる -
v-model
は上記のシンタックスシュガー- input の value に自動的に紐付ける
- checkbox とか他の input にも紐付けられる
- ★ これをしない場合は更新メソッドを methods に定義して input に v-on で紐付けないといけない
- v-model をすると勝手に紐付いて更新してくれる
- Formデータを送信するときに自動で紐付け・反映してくれるから、そういうときに使うのかなと想像している
Step6
-
v-if
は条件分岐 -
v-else-if
,v-else
がある
Step7
-
v-for
- リスト表示
Step8
- Computed Property
- 他のプロパティから計算される state をリアクティブに反映したプロパティを宣言できる
- ★ data に定義した値を処理して要素を絞り込むとかを定義するものだと思う
- checkbox に v-model を設定すると boolean をいい感じで紐付けてくれる
Step9
-
ref
属性-
mounted
の中でthis.$refs
で参照できる- ライフサイクルフックと呼ばれるもので、コンポーネントのライフサイクルの特定のタイミングで呼び出されるコールバックを登録することができる
- 他にもcreatedやupdatedなどのフックがある
- Lifecycle Diagram
-
Template Refs
- ★ なんかいろいろあるけどあとで読んでおく
-
Step10
-
Watchers
- data で設定した property を監視する
- 変更があったらそれを元に処理できる
-
count
ってプロパティがあった場合、count(newCount)
で更新があった値を取得できる - ★ 例に
mounted
があるけど、watchしてるときに this.fetchData() してるんで二重に動いてる気がする- そんなことないな、
mounted
はレンダリングされた直後に一回だけ動く - その後で変更があったら watch が動いてる感じ
- そんなことないな、
Step11
- Components
- 入れ子にコンポーネントを使うことができる
- ★ コンポーネントにスタイルとかいろいろ閉じ込められるからいい感じで使い回せる様になるんだと思う
Step12
- Props
- 親から子へ、props を通して値を渡せる
-
props: { msg: String }
みたいな感じで型を定義できるっぽい - ★
this.msg
みたいな感じで使えるんだと思う - ★ 例では
:msg="greeting"
って binding してる- これをすると data と紐づくっぽい
-
msg="greeting"
みたいに:
にすると binding しないので単に "greeting" って文字が表示される
Step13
- Emits
- 子から親にイベントを送る
- 子に emits: ['response'] を定義
- 子に this.$emit('response', 'hellow from child')
- 最初の引数が emits で定義したものに対応してる
- それ以降の引数が親の event listener に送られる
- 親は v-on(@) で受ける
@response="(msg) => childMsg = msg"
Step14
- Slots
- slots を通して親から子にtemplate fragments を渡せる
- template fragments: テンプレートの破片、任意のHTMLだと思う
- 子は
<slot />
で受け取ったものを出力できる-
<slot>Fallback content</slot>
みたいに中に入れると親から slot が送ってこなかった場合に表示するものをおける
-
- slots を通して親から子にtemplate fragments を渡せる
Quick Start
-
https://vuejs.org/guide/quick-start.html
- この例では Composition API を使っている
- ★ index.html がエントリーポイントっていうのか?これが軸になってる
- ここで main.js を読んでる
-
createApp(App).mount('#app')
で index の #app を mount してアプリを表示してる - この
App
が RootComponent になってる
-
- ここで main.js を読んでる
- 以下みたいに複数の Vue app を同じページで動かせる
const app1 = createApp({
/* ... */
})
app1.mount('#container-1')
const app2 = createApp({
/* ... */
})
app2.mount('#container-2')
-
nextTick()
- https://vuejs.org/api/general.html#nexttick
- ★ 変なタイミングで更新されるパラメータがあったときに反映待ちをいい感じでしてくれる気がする
-
computed と methods の違い
- computed の結果はキャッシュされるので再レンダリングされるときは同じ値になる
- methods はキャッシュされないので再レンダリングの際は再計算される
Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as author.books has not changed, multiple access to publishedBooksMessage will immediately return the previously computed result without having to run the getter function again.
This also means the following computed property will never update, because Date.now() is not a reactive dependency:
computed: {
now() {
return Date.now()
}
}
In comparison, a method invocation will always run the function whenever a re-render happens.
- v-show と v-if
- 一般的に、v-ifはトグルコストが高く、v-showは初期レンダリングコストが高いと言われています。そのため、頻繁に何かを切り替える必要がある場合はv-showを、実行時に条件が変化する可能性が低い場合はv-ifを選択します。
- ★ v-show は
display:none
になるので表示の切り替えコストは少ない- v-if は html要素ごと消すのでレンダリングコストが掛かるってことだと思う
-
Mutation Methods
- これらが使われるとVueは変更検知する
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
- これらが使われるとVueは変更検知する
-
Non-mutating Methods
- 新しい配列が生成されて返される
- filter()
- concat()
- slice()
- ★ この場合もVueがいい感じに扱ってくれて既存レンダリングされたものを使って処理してくれるっぽい
- 新しい配列が生成されて返される
-
computed プロパティでの注意
- reverse() と sort() には注意が必要
- この2つのメソッドは、元の配列を変化させるので、計算されたゲッターでは避けるべき
- これらのメソッドを呼び出す前に、元の配列のコピーを作成する
- return numbers.reverse()
+ return [...numbers].reverse()
- inline handler で引数とイベントを取りたいとき
- $event で取れる
<!-- using $event special variable -->
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
<!-- using inline arrow function -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>
methods: {
warn(message, event) {
// now we have access to the native event
if (event) {
event.preventDefault()
}
alert(message)
}
}
-
- ★ prevent はなんとなく分かるけど、それ以外は動かして確認するのが良さそう
- 初見ではちょっと理解できない...
- ★ prevent はなんとなく分かるけど、それ以外は動かして確認するのが良さそう
-
- キーボード操作イベントを捕まえるやつ
- ★ 例とかみるといろいろあるので、必要に合わせて使っていく
-
- ★ 例がたくさんあるので Form 処理するときは参考にすると良さそう
-
- ★ 以下の画像を頭に入れておけば大丈夫そう
- ★ 以下の画像を頭に入れておけば大丈夫そう
-
- プロパティの変更を検知する
- ★ data とかで定義したプロパティをメソッド名にすればあとは勝手に監視してくれるんだと思う
- nested されたプロパティの変更は監視しない
- deep watcher を使う必要がある(
deep: true
を設定すれば監視してくれる?)- 大きいobjectだったらパフォーマンスに影響があるかも
- deep watcher を使う必要がある(
- watch はデフォルトで lazy
- すぐに見たい場合は
immediate: true
を設定すればいい
- すぐに見たい場合は
- デフォルトでは、ユーザーが作成したwatcher callback は、Vueのコンポーネントが更新される前に呼び出される
- ウォッチャーコールバックの内部でDOMにアクセスしようとすると、DOMはVueが何らかの更新を適用する前の状態になる
- Vueが更新した後にウォッチャーコールバックでDOMにアクセスしたい場合は、flush: 'post' オプションを指定する必要がある
- プロパティの変更を検知する
-
- ★ HTML DOMを直接参照するんだと思う
- 例がいろいろあがってるのであとでちゃんと見る
- ★ HTML DOMを直接参照するんだと思う
-
- ★ 例がいろいろあがってるのであとでちゃんと見る
ここから先は Component の詳細になっていくので一旦保留
Nuxt に移る
Nuxt3
- pages ディレクトリ
- ページの URL に対応するファイル名.vue を作ると自動的にルーティングされる
- components ディレクトリ
- コンポーネントを入れるディレクトリで、自動的に import される
- pages のファイルで import とか書かなくても読み込んでくれるので使えるっぽい
- コンポーネントを入れるディレクトリで、自動的に import される
- App.vue
- Nuxt の一番のルートコンポーネント
- `NuxtPage タグを入れると pages ディレクトリの内容が反映されてルーティングが効くっぽい
- Nuxt の一番のルートコンポーネント