More Related Content Similar to はじめようVue3!ハンズオンでとらのあなラボのフロントエンドを学ぶ_20210611_TechDay#1 (20) はじめようVue3!ハンズオンでとらのあなラボのフロントエンドを学ぶ_20210611_TechDay#11. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
はじめようVue3!
ハンズオンでとらのあなラボのフロントエンドを学ぶ
虎の穴ラボ 藤原 佳顕
1
2. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
アジェンダ
● 自己紹介
● なぜVue(3)か
● とらのあなラボでのVue(3)活用
● 今回利用する環境について
● TypeScriptについて(今回は割愛)
● Vue3ハンズオン
● まとめ
2
3. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
自己紹介
● 名前:藤原 佳顕
● 所属:虎の穴ラボ
● やっていること:(Fantia、)新規サービス、社内ツール、ソースレビュー
● 好きなもの:RustとかClojureとかDenoとか
● 好きなもの2:STG、音ゲー、格ゲー
3
4. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
なぜVue3か
● 一時期のフレームワークが群雄割拠していた時代に比べて、ほぼReact、Vue、Angularの
いずれかで安定している
● とはいえ、ライブラリ、フレームワーク自体のアップデートはそれなりに早い
○ ソースの記述が古くなる可能性が高い
○ 安定している or するだろうものであれば取り入れてしまったほうが良い
● 周辺ツールも同様の傾向
○ Vue3から推奨ツールがvue cli→viteに
4
5. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
虎の穴ラボでのVue(3)活用
5
● 新規プロジェクト(Nuxt.js)
● 社内の稼働時間管理ツール(Vue2→Vue3)
○ Vue2(Vue class component)からVue3にアップデート
● 社内のプロジェクト管理ツール(Vue3)
○ 作成段階からcomposition apiを利用
9. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
今回利用する環境
9
● macOS Big Sur
● TypeScript v4.1.3
● Node.js 14.17.0
○ これはインストールが必要です
○ docker用ファイルも用意してるのでそちらの利用でも構いません
● Vue 3.0.5
● Vite 2.3.3
10. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け
10
// 型はコロン(:)のあとに後置する形
// この関数はidという名前のnumber型の引数とnameという名前のstring型引数を取って、stringを返す関数
// ?がつく場合はオプションの引数となり渡さなくて良くなるが、関数内でチェックが必要
const hoge = (id: number, name: string, desc?: object): string => {
let keys: string[] = [];
if (desc) {
keys = Object.keys(desc);
}
return `id: ${id}, name: ${name}, desc_keys: ${keys}`;
};
// 型が推論できる場合は明示は不要
const a = 100;
const b = "toranoana";
// 型がわからないときは
any型になる(基本非推奨)
const c: any = { a: 123, b: { c: 200 } };
console.log(hoge(a, b));
// any型だとどこにでも入れられてしまう
console.log(hoge(a, b, c));
11. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け
11
// interfaceを使ってobjectなどに具体的な型を付けられる
interface Fuga {
ham: number;
spam: number;
storeName: string;
}
// interfaceを使った変数宣言 ?付きのオプションメンバー以外はすべてのメンバーが存在しないといけない
const meatStore: Fuga = { ham: 100, spam: 200, storeName: "駅前肉屋" };
12. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け
12
const meatMap = (store: Fuga) => {
console.log(`${store.storeName}にはhamが${store.ham}個、spamが${store.spam}個ありま
す。`);
}
meatMap(meatStore);
// ダックタイピングにより構造が一致してさえいれば呼び出せる
meatMap({ham: 1, spam: 2, storeName: "2丁目肉屋" });
// Type Aliasという機能もあるが、基本的には interfaceをベースに使ったほうが良い
// 長い名前に別名を付けたいときなどに利用
type FugaFuga = Fuga;
13. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け
13
// 特集な型その1:インデックスシグネチャ 以下は数値のキーに対して文字列のvalueが紐づくオブジェクトです
const ranking: { [key: number]: string } = { 1: "aさん" };
ranking[2] = "Bさん"; // ranking["3"] = "Bさん"; // keyにnumber以外を渡すとエラー
14. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け
14
// 特集な型その2:ユニオン型
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle; // パイプ(|)で区切ることでAかBという型を表現できる
function menseki(s: Shape): number {
if (s.kind === "square") {
return s.size * s.size;
}
return s.width * s.height;
}
15. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ハンズオンについて
15
● メインの対象者
○ フロントエンドあまり触ったこと無い方
○ Vue2はやってたけどVue3のアップデートにあまり知らない方
● 目標
○ 実際にVue3でアプリを作るときに大抵のことでは困らなくて良くなる
● ソースコードはこちら
○ https://github.com/toranoana/vue3-handson
16. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ブランチまたはディレクトリ名:資料の見方とサンプルの動かし方
16
● サンプルリポジトリを動かすには、以下の手順が必要です
○ package.jsonがあるディレクトリでnpm install
○ package.jsonがあるディレクトリでnpm run dev
○ http://localhost:3000にアクセス
○ dockerの環境も用意してますので、詳細はREADMEをお読みください
● 以降ではタイトルの左側に現在作業中のディレクトリ名を表示します
○ リポジトリのディレクトリを参照してください
○ 実際に手を動かさない場合でも対象のディレクトリを参照していただくことで何をしているか
わかるかと思います
17. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
注意点と進め方
17
● 各ディレクトリで初回で動かす場合はディレクトリごとにnpm installが必要です
● 00.init_templateが初期状態のディレクトリです
○ こちらを拡張することでハンズオンを進めていきます
● ソースを手打ちしていただいても良いですが、各ディレクトリのサンプルをコピペしていただいても問題ないです
● ソース及び発表資料は公開いたしますので、途中でついていけなくなった方などは後日参照いただければと思い
ます
● 割愛させて頂く部分が発生するかもしれませんが、その際も公開された資料をご確認ください
● 今回は申し訳ありませんが、環境が動かない等のフォローはできない可能性があります。その際はソースの方を
追っていただければと思います
18. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
18
1. コンポーネントの基本(basic_of_component)
2. stateについて
3. イベントについて
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて←ここまでは実施予定
7. 非同期通信(Ajax)
8. computedとwatch
9. ルーティング
19. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
basic_of_component:コンポーネントの基本
19
● Vue.jsはWebコンポーネントとVirtual DOMを軸にしたフレームワークです
○ Reactや、Angular(2以降)と似たフレームワークです
● *.vueという拡張子のファイルが画面の1パーツ(コンポーネント)となります。以下例です
○ Button.vue:ボタンのコンポーネント
○ Header.vue:ヘッダーのコンポーネント
○ App.vue:Button.vueとHeader.vueを組み合わせて画面を作るコンポーネント
20. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue:ディレクトリ構成
20
❯ tree -L 2
.
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── public
├── src
│ ├── App.vue
│ ├── assets
│ ├── components
│ ├── main.ts
│ ├── router
│ ├── shims-vue.d.ts
│ ├── store
│ └── views
├── tsconfig.json
└── vite.config.ts
コンポーネントのエントリポイント
プログラムのエントリポイント
ルーティングに関するファイル置き場
*.vueファイルをTypeScriptに認識させるための型定義
Vuexに関するファイル置き場
URLと紐づくコンポーネントの置き場
小分けされたコンポーネント置き場
画像などの静的なファイル置き場
21. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
basic_of_component:コンポーネントの基本
21
<template>
<div id="app">
<div id="nav">
<!-- router/index.tsにかかれているルーティング情報から自動で
aタグを作る -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<!-- ルーティングされたコンポーネントがここに描画される-->
<router-view />
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "App",
});
</script>
22. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
basic_of_component:コンポーネントの基本
22
App.vue
router-link x 2
router-view
HelloWorld.vue
24. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
24
1. コンポーネントの基本
2. stateについて(state)
3. イベントについて
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて
7. 非同期通信(Ajax)
8. computedとwatch
9. ルーティング
25. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
state:stateについて
● setupメソッド
○ 各コンポーネントのエントリポイントとなるメソッド
○ 呼ばれた段階ではまだレンダリングされていない状態
● reactive関数
○ リアクティブなオブジェクトを作成できる
○ リアクティブな状態が変化するとビューが自動的に更新される
○ state.messageを更新すると、template側でstate.messageを使ってる部分も自動で変わる(後述)
25
26. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
state:stateについて
<template>
<div id="app">
<div id="nav">
<!-- 追加 -->
<p>{{ state.message }}</p>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template>
26
<script lang="ts">
import { defineComponent, reactive } from "vue";
interface State {
message: string;
}
export default defineComponent({
name: "App",
setup() {
const state = reactive<State>({
message: "Hello Sample"
});
return { state };
}
});
</script>
27. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
state:stateについて
一番上に”Hello Sample”が追
加される
27
28. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
28
1. コンポーネントの基本
2. stateについて
3. イベントについて(event)
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて
7. 非同期通信(Ajax)
8. computedとwatch
9. ルーティング
29. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて
<template>
<div id="app">
<div id="nav">
<p>{{state.message}}</p>
<!-- 追加 -->
<p>
<button type="button" @click="onClick">メッセージを変更 </button>
</p>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template 29
30. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて
export default defineComponent({
name: "App",
setup() {
const state = reactive<State>({
message: "Hello Sample"
});
// 追加
const onClick = () => {
state.message = "clicked";
};
return {
state,
// 追加
onClick
};
}
}); 30
31. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて
● 関数の作り方
○ setup関数内で関数を作り、戻り値として返す
○ template内で@clickなどで関数をイベントを紐付けする
○ reactiveな値と共に別ファイルに書くこともできる(次ページ)
● 表示の更新について
○ reactiveで生成した変数を、関数内で更新すると自動でtemplate内の表示も変わる
○ element.innerHTMLなどを利用した直接的なDOM書き換えは不要
31
32. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて
import { AppState, useAppState } from './utils';
type State = AppState
export default defineComponent({
name: "App",
components: { Sample, Async },
setup() {
const [state, onClick] = useAppState();
return {
state,
onClick
};
}
});
32
reactiveな値と、値を変更する処理を別ファイルに書くこともでき る例(utils.ts)
import { reactive } from "vue";
export interface AppState {
message: string;
}
export const useAppState = (): [AppState, () => void] => {
const state = reactive<AppState>({
message: "Hello Sample",
});
const onClick = () => {
state.message = "clicked";
};
return [state, onClick];
};
33. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
33
1. コンポーネントの基本
2. stateについて
3. イベントについて
4. コンポーネント間の連携(component_props)
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて
7. 非同期通信(Ajax)
8. computedとwatch
9. ルーティング
34. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_props:コンポーネント間の連携
34
components/Sample.vueを作成
<script lang="ts">
import { defineComponent } from "vue"
interface State {
localMessage: string;
}
export default defineComponent({
props: {
parentMessage: {
type: String,
required: true,
},
},
setup() {
const state = reactive<State>({ localMessage: "child component" });
return { state };
},
});
</ script>
<template>
<div>
<p>localMessage: {{ state.localMessage }}</p>
<p>parentMessage: {{ parentMessage }}</p>
</div>
</template>
35. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_props:コンポーネント間の連携
<template>
<div id="app">
<div id="nav">
<!-- 追加 -->
<sample :parent-message="state.message" />
<!-- <p>{{ state.message }}</p> -->
<!-- 以下略 -->
</template>
35
<script lang="ts">
import { defineComponent, reactive } from "vue";
import Sample from './components/Sample.vue';
interface State {
message: string;
}
export default defineComponent({
name: "App",
// 追加
components: { Sample },
// 以下略
});
</script>
App.vueを変更
36. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_props:コンポーネント間の連携
● props
○ 親コンポーネントから渡ってくるデータ。変更不可
■ 変更したい場合は変更用の処理を一緒に渡す(後述)
○ プリミティブな値だけでなく、objectや関数も渡せる
● 子コンポーネントの埋め込み方
○ defineComponent内にcomponentsプロパティを追加
○ template内でカスタムタグのように子コンポーネントを埋め込み
● propsの渡し方について
○ :`props名` で受け渡す
■ v-bind:`prps名` のシンタックスシュガー
36
37. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue:コンポーネント間の連携
37
子コンポーネント(Sample.vue)内で親(App.vue)から渡された
propsが表示される
親での変更がpropsにも反映され、表示が変わる
38. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
38
1. コンポーネントの基本
2. stateについて
3. イベントについて
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更、component_events)
6. ライフサイクルについて
7. 非同期通信(Ajax)
8. computedとwatch
9. ルーティング
39. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)
39
Sample.vueを変更
<template>
<div>
<p>localMessage: {{ state.localMessage }}</p>
<p>parentMessage: {{ parentMessage }}</p>
</div>
<!-- 以下追加 -->
<p>
<button type="button" @click="updateMessage">propで更新</button>
</p>
<p>
<button type="button" @click="emitClick">emitで更新</button>
</p>
</template>
40. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)
40
Sample.vueを変更
propsで変更用の関数を受け取る場合と、Eventで受け取る場合を追加
<script lang="ts">
// 略
export default defineComponent({
props: {
// 略
// 追加(propsで変更用の関数を受け取るケース
)
updateMessage: {
type: Function as PropType<() => void>,
default: () => {},
},
},
emits: ["click"],
setup(_, { emit }: SetupContext) {
// 略
// 追加(Eventとして変更用の関数を受け取るケース
)
const emitClick = () => {
emit("click");
};
return {
state,
emitClick, // 追加
};
},
});
</script>
41. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)
41
App.vueを変更
propsとEventを渡すようにする
<template>
<div id="app">
<div id="nav">
<!-- 追加(propsと@click) -->
<sample
:parent-message="state.message"
@click="onChildEmit"
:update-message="onChildClick"
/>
<!-- 以下略 -->
</template>
<script lang="ts">
// 略
export default defineComponent({
// 略
setup() {
// 略
// 追加(2つ)
const onChildClick = () => { state.message = "child clicked"; };
const onChildEmit = () => { state.message = "child emit clicked"; };
return {
state, onClick,
// 追加(2つ)
onChildClick,
onChildEmit,
};
},
});
</script>
42. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)
42
43. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)
● propsとして関数受け渡し
○ typeにFunctionを指定することでpropsとして関数を受け取れるようにする
○ 関数の具体的な型はPropTypeを使うことで明示できる
● Eventとしての関数受け渡し
○ defineComponentのプロパティとしてemitsを追加(Vue3から)
■ 呼び出す可能性のあるEvent一覧を文字列で追加
■ objectで指定することで引数等のバリデーションも可能(今回は割愛)
○ setup関数の第二引数、SetupContextのメンバーとしてemit関数がある
○ emit(`呼びたいEvent名`, `引数`)で関数呼び出しできる
■ 文字列で関数を呼び出すため具体的な型がつけにくい
43
44. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
44
1. コンポーネントの基本
2. stateについて
3. イベントについて
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて(lifecycle)
7. 非同期通信(Ajax)
8. computedとwatch
9. ルーティング
45. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
lifecycle:ライフサイクルについて
● ReactやAngularなどと同様にライフサイクルがあります
○ https://v3.vuejs.org/guide/composition-api-lifecycle-hooks.html
○ Vue2であったcreatedはsetupに統合されました
● よく使うもの
○ mounted
■ DOMに触れられるようになったタイミングで発火
○ unmounted
■ コンポーネントが破棄されるとき
■ windowに何かしらイベント付けてるときの破棄などに使う(メモリリーク防止)
45
46. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
lifecycle:ライフサイクルについて
46
views/Home.vueを変更
<script lang="ts">
// ライフサイクルのHookメソッドを追加
import { defineComponent, onMounted, onUnmounted } from "vue";
import HelloWorld from "../components/HelloWorld.vue";
export default defineComponent({
// 略
// setupメソッド追加
setup() {
const resizeEvent = () => { console.log("resize window"); };
onMounted(() => {
window.addEventListener("resize", resizeEvent);
});
onUnmounted(() => {
window.removeEventListener("resize", resizeEvent);
});
},
});
</script>
48. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
48
1. コンポーネントの基本
2. stateについて
3. イベントについて
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて
7. 非同期通信(ajax)
8. computedとwatch
9. ルーティング
49. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)
● 生のXMLHttpRequestやfetch APIも使えますが、今回はライブラリを利用します
○ https://github.com/axios/axios
○ npm install axios @types/axios
○ サンプルのリポジトリにはインストール済みです
○ コンポーネントマウント前にデータ取得開始→state変更といった流れにします
49
50. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)
50
● 今回はBitCoinの金額を取得するAPIを利用します(coindesk api)
○ https://api.coindesk.com/v1/bpi/currentprice.json
APIのレスポンスの型は次のものを想定
interface Time {
updated: string;
updatedISO: string;
updateduk: string;
}
interface Bpi {
code: string;
symbol: string;
rate: string;
description: string;
rate_float: number;
}
interface CurrentPrice {
time: Time;
disclaimer: string;
chartName: string;
bpi: {
USD: Bpi;
GBP: Bpi;
EUR: Bpi;
};
}
51. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)
51
components/Async.vueを作成
<template>
<pre v-if="state.apiData">
<code>
{{ state.apiData }}
</code>
</pre>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
import axios from "axios";
// APIのinterfaceは略(前ページ参照)
interface State {
apiData: CurrentPrice | null;
}
export default defineComponent({
setup() {
const state = reactive<State>({ apiData: null });
axios
.get<CurrentPrice>("https://api.coindesk.com/v1/bpi/currentprice.json")
.then((res) => { state.apiData = res.data; });
return { state, };
},
});
</script>
<style scoped>
pre {
height: 300px;
overflow: scroll;
border: solid 1px #8a8a8a;
}
</style>
52. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)
52
App.vueに追記
<template>
<div id="app">
<div id="nav">
<!-- 略 -->
<async />
<!-- 略 →
</div>
<router-view />
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted, reactive } from "vue";
import Sample from "./components/Sample.vue";
// 追加
import Async from "./components/Async.vue";
interface State {
message: string;
}
export default defineComponent({
name: "App",
// Async追加
components: { Sample, Async },
// 略
});
</script>
54. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajaxおまけ)
54
setup関数をasyncにしたい場合(Async.vue)
export default defineComponent({
async setup() {
const state = reactive<State>({ apiData: null });
const res = await axios.get<CurrentPrice>("https://api.coindesk.com/v1/bpi/currentprice.json");
state.apiData = res.data;
return {
state,
};
},
});
55. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajaxおまけ)
55
App.vueでAsyncコンポーネントをSuspenseで囲む
<template>
<!-- 略 -->
<!-- 追加:Supenseで囲むことで非同期コンポーネントのフォールバックコンテンツを表示
-->
<Suspense>
<template #default>
<async />
</template>
<template #fallback>
<div>loading...</div>
</template>
</Suspense>
<!-- 略 -->
</template>
56. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)
● async setupとする場合はSuspenseが必要
○ https://v3.ja.vuejs.org/guide/migration/suspense.html
● Suspense自体は非同期コンポーネントの描画を待つ間、代わりを表示する機能
○ Suspenseなしasync setupなコンポーネントの部分は何も描画されなくなります
● Vue2でのasync createdのつもりで使うと引っかかるかもしれないので注意
56
57. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
57
1. コンポーネントの基本
2. stateについて
3. イベントについて
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて
7. 非同期通信(Ajax)
8. computedとwatch(computed_and_watch)
9. ルーティング
58. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
computed_and_watch:computedとwatch
58
Sample.vueに追記
<div>
<!-- 以下2つに変更 -->
<p>{{ localFullMessage }}</p>
<p>{{ parentFullMessage }}</p>
</div>
<p>
<button type="button" @click="updateMessage">propで更新</button>
</p>
<p>
<button type="button" @click="emitClick">emitで更新</button>
</p>
</template>
59. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
computed_and_watch:computedとwatch
59
// computedとwatchとwatchEffect追加
import { computed, watch, watchEffect, /* 略 */ } from "vue";
// 略
export default defineComponent({
// 略、propsをsetupの引数に追加
setup(props, { emit }: SetupContext) {
const state = reactive<State>({
localMessage: "child component"
});
// 以下色々追加
const localFullMessage = computed(
() => `localMessage: ${state.localMessage}`
);
const parentFullMessage = computed(
() => `parentMessage: ${props.parentMessage}`
);
watchEffect(() => {
alert(
`localMessageかparentMessageが変更されました。
${localFullMessage.value}
${parentFullMessage.value}`
);
});
watch(
() => props.parentMessage,
() => alert("parentMessageが変更されました。 ")
);
const emitClick = () => { emit("click"); };
return {
// 追加(localFullMessage、parentFullMessage)
state, emitClick, localFullMessage, parentFullMessage,
};
},
});
</script>
60. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
computed_and_watch:computedとwatch
● watch、watchEffectを使うことでデータの監視が可能
○ watchEffect:コールバックに指定した関数の中で使ってるリアクティブな変数が変更されたら関数
を再度実行する
○ watch:第一引数に指定した変数が変更されたら第2引数の関数を再度実行する
● computedを使うことでデータに加工が可能
○ 不変でreactiveなrefオブジェクトを返す関数
○ computed内で使ってる変数が変更されると戻り値もリアクティブに変更される
60
61. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
vue
61
1. コンポーネントの基本
2. stateについて
3. イベントについて
4. コンポーネント間の連携
5. コンポーネント間の連携その2(propsの変更)
6. ライフサイクルについて
7. 非同期通信(Ajax)
8. computedとwatch
9. ルーティング(routing)
62. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
routing:ルーティング
62
<template>
<div>Topページ</div>
<Suspense>
<template #default>
<async />
</template>
<template #fallback>
<div>loading...</div>
</template>
</Suspense>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Async from "../components/Async.vue";
export default defineComponent({
components: { Async },
});
</script>
URLとコンポーネントを紐付けるために、views/Top.vueを作成
中身では先程作成したAsync.vueを表示してみます
63. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
routing:ルーティング
63
// 略
const routes: RouteRecordRaw[] = [
{ path: '/', component: Home },
{ path: '/about', component: About },
// 追加
{ path: '/top', component: Top },
];
export const router = createRouter({
history: createWebHistory(),
routes,
});
<template>
<div id="app">
<div id="nav">
<!-- 略 -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<!-- 追加 -->
<router-link to="/top">Top</router-link>
</div>
<router-view />
</div>
</template>
続いて、router/index.tsとApp.vueを変更
(router/index.ts)
(App.vue)
65. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
routing:ルーティング
65
● 各パスに1コンポーネントが紐づく形になります
○ 指定したコンポーネントがApp.vueの<router-view />に入ります
● コンポーネントを非同期ロードすることも可能
○ ダイナミックインポートしたコンポーネントをパスに紐付ける
○ 画面ロード時のファイルサイズを小さくすることができる
{ path: '/top', component: () => import(/* webpackChunkName: "top" */ '../views/Top.vue') },
66. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
まとめ
66
● Vue3と各機能について説明しました
○ 単一コンポーネント内で完結するstateと更新処理について説明しました
○ propsやeventを通したコンポーネント間の連携について説明しました
○ Vue3は昨年リリースされたばかりの新しいフレームワークです
○ Vue3での実際のアプリケーションの使い方について説明しました
○ 説明してませんが、周辺ライブラリがVue3の記述に追いついてない場合があるので注意
○ 公開するスライドには説明しなかった部分も含まれるのでぜひ見てみてください