Vue3 システム学習#
1. Vue3 基礎#
1.1 ループレンダリング#
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
key について話しましょう、なぜ key を追加する必要があるのか?
key は状態を管理するために使用されます。つまり、v-for でリストや配列をバインドする場合です。
デフォルトモードでは、key を加えない場合、データの順序が変わると、vue は DOM の流れの順序を移動せず、各要素を再更新します。
ただし、リストのレンダリング出力結果が子コンポーネントの状態や一時的な DOM 状態(例えばフォーム入力値の状況)に依存する場合、
Vue に各ノードの識別を追跡できるようにヒントを与えるために、各要素に対応するブロックに一意の key 属性を提供する必要があります。
1.2 イベント処理#
イベントハンドラー(handler)の値は次のようになります:
- インラインイベントハンドラー:イベントがトリガーされたときに実行されるインライン JavaScript 文(onclick に似ています)。
- メソッドイベントハンドラー:コンポーネント上で定義されたメソッドへのプロパティ名またはパス。
インラインイベントハンドラーとメソッドイベントハンドラーとは?#
インラインイベントハンドラーとメソッドイベントハンドラーは、HTML 要素のイベントを処理するための JavaScript の 2 つの主要な方法です。
インラインイベントハンドラー
インラインイベントハンドラーは、HTML 要素のタグ内で直接指定されます。ユーザーがその要素に対して操作を行うと(クリックなど)、対応するイベントがトリガーされます。インラインイベントハンドラーの典型的な例はonclick
属性で、要素の HTML タグ内で直接設定できます。例えば:
<button onclick="alert('ボタンがクリックされました!')">クリックしてください</button>
このコード内のonclick
属性はインラインイベントハンドラーであり、ボタンがクリックされたときに実行される JavaScript コードを定義しています。
メソッドイベントハンドラー
メソッドイベントハンドラーは、JavaScript コードを使用して要素にイベント処理関数をバインドします。この方法は通常、より柔軟で管理が容易であり、特に複雑なアプリケーションにおいて便利です。JavaScript 内でaddEventListener
メソッドを使用して要素にイベントハンドラーを追加できます。例えば:
const name = ref('Vue.js')
function greet(event) {
alert(`こんにちは ${name.value}!`)
// `event` はDOMのネイティブイベントです
if (event) {
alert(event.target.tagName)
}
}
<!-- `greet` は上で定義したメソッド名です -->
<button @click="greet">挨拶</button>
このコードはまずgetElementById
を使用して ID がmyButton
の要素を取得し、次にaddEventListener
を使用してその要素にクリックイベントハンドラーを追加します。ボタンがクリックされると、警告ボックスが表示されます。
全体的に、インラインイベントハンドラーは迅速に実装できるが、特に大規模なプロジェクトではメンテナンスが難しいです。一方、メソッドイベントハンドラーはより多くの JavaScript コードを書く必要がありますが、より高い柔軟性とメンテナンス性を提供します。
1.3 フォーム入力バインディング#
v-model は数値、文字列、ブール値、配列、オブジェクト、カスタムコンポーネントなどをバインドします。
- テキスト
- 文字列形式
- 複数行テキスト
- 文字列形式
- チェックボックス
- 単一のブール型値をバインド
- 複数のチェックボックス
- 同じ配列または集合の値に複数のチェックボックスをバインド
<div>チェックされた名前: {{ checkedNames }}</div> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label>
- ラジオボタン
- 単一の値にバインド
<div>選択された: {{ picked }}</div> <input type="radio" id="one" value="One" v-model="picked" /> <label for="one">One</label> <input type="radio" id="two" value="Two" v-model="picked" /> <label for="two">Two</label>
- セレクター
- v-model 式の初期値がどの選択肢とも一致しない場合、
<select>
要素は「未選択」の状態としてレンダリングされます。iOS では、これによりユーザーが最初の項目を選択できなくなります。なぜなら、iOS はこの場合に change イベントをトリガーしないからです。したがって、上記の例のように空の値の無効なオプションを提供することをお勧めします。<select v-model="selected"> <option disabled value="">選択してください</option> <option>A</option> <option>B</option> <option>C</option> </select> <span>選択された: {{ selected }}</span>
- v-model 式の初期値がどの選択肢とも一致しない場合、
2. コンポーネントシステム学習#
2.1 コンポーネントデータの受け渡し#
コンポーネント間のデータの受け渡しには 2 つの方法があります:
- 親コンポーネントから子コンポーネントへデータを渡す
defineProps を使用してデータを渡します:// 親コンポーネント内 <template> <ChildComponent :title="title" /> </template> <script> import ChildComponent from './ChildComponent.vue' </script>
// 子コンポーネント内 <script setup> import { defineProps } from 'vue' const props = defineProps({ title: String }) </script>
- 子コンポーネントから親コンポーネントへデータを渡す
- カスタムイベントを通じて親コンポーネントにデータを渡す
Vue 3 では、子コンポーネントはカスタムイベントを通じて親コンポーネントにデータを渡すことができます。このプロセスは通常、以下のいくつかのステップを含みます:
- カスタムイベントを通じて親コンポーネントにデータを渡す
-
子コンポーネント内:
emit
メソッドを使用してカスタムイベントをトリガーし、データを引数として渡します。```vue // 子コンポーネント内 <!-- BlogPost.vue, <script>は省略 --> <template> <div class="blog-post"> <h4>{{ title }}</h4> <button @click="$emit('enlarge-text')">テキストを拡大</button> </div> </template> ```
Vue では、カスタムコンポーネントはイベントを通じてデータを転送できます。あなたの例では、コンポーネントは$emit
メソッドを使用してenlarge-text
イベントをトリガーしました。イベントをトリガーする際にデータを親コンポーネントに渡す必要がある場合、データを$emit
メソッドの第 2 引数として渡すことができます。
以下は、enlarge-text
イベントをトリガーする際にデータを持たせるためにコンポーネントテンプレートを修正する方法です:
<template>
<div class="blog-post">
<h4>{{ title }}</h4>
<!-- データを$emitの第2引数として追加 -->
<button @click="$emit('enlarge-text', someData)">テキストを拡大</button>
</div>
</template>
-
親コンポーネント内:このカスタムイベントをリスンし、イベントハンドラを通じてデータを受け取ります。
```vue <BlogPost ... @enlarge-text="postFontSize += 0.1" /> ```
<!-- 親コンポーネントテンプレート --> <template> <div> <your-component @enlarge-text="handleEnlargeText"></your-component> </div> </template> <script> export default { methods: { // イベントハンドラメソッドが渡されたデータを引数として受け取ります handleEnlargeText(data) { // ここで受け取ったデータを処理します console.log(data); } } } </script>
@enlarge-text="postFontSize += 0.1"のリスニングにより、親コンポーネントはこのイベントを受け取り、postFontSizeの値を更新します。
簡単に言えば、vueではkeyを通じてemitを使用して**カスタムイベント**と**操作**を関連付け、親コンポーネントで**@を通じてこのカスタム**イベントをリスンし、**リスニングしたイベント内で**データを処理します。
したがって、Vueでコンポーネントのトリガーを作成したい場合は、$emitを使用してコンポーネントのトリガーを定義します。
- 双方向バインディングを通じて親コンポーネントにデータを渡す
```vue
<!-- Child.vue -->
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>親がバインドしたv-modelは: {{ model }}</div>
</template>
<!-- Parent.vue -->
<Child v-model="count" />
defineModel () が返す値は ref です。これは他の ref と同様にアクセスおよび変更できますが、親コンポーネントと現在の変数間の双方向バインディングの役割を果たします:
その.value と親コンポーネントの v-model の値は同期します;
子コンポーネントで変更されると、親コンポーネントにバインドされた値も更新されます。
v-model は引数を受け取ります。
コンポーネント上の v-model も引数を受け取ることができます:
<UserName
v-model:first-name="first"
v-model:last-name="last"/>
<MyComponent v-model:title="bookTitle" />
子コンポーネント内では、文字列を最初の引数としてdefineModel()に渡すことで、対応する引数をサポートできます:
<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>
<template>
<input type="text" v-model="title" />
</template>
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>
<template>
<input type="text" v-model="firstName" />
<input type="text" v-model="lastName" />
</template>
2.2 コンポーネントイベント学習#
- $emit メソッドを通じてイベントをバインドします。以下はボタンのタッチと someEvent というイベントをバインドしたものです。
<!-- MyComponent -->
<button @click="$emit('someEvent')">クリックしてください</button>
親コンポーネントは@/v-onを通じてイベントをリスンします
<MyComponent @some-event="callback" />
<MyComponent @some-event.once="callback" />
この親コンポーネントのリスニングを通じて、子コンポーネントが親コンポーネントのコールバックをトリガーする機能を実現できます。
2. コンポーネントが親コンポーネントのコールバックにデータを持たせる場合はどうしますか?
<button @click="$emit('increaseBy', 1)">
1増やす
</button>
<MyButton @increase-by="(n) => count += n" />
または
<MyButton @increase-by="increaseCount" />
function increaseCount(n) {
count.value += n
}
つまり、emit の第 2 引数はコールバックに持たせる数値であり、関数の引数として受け取ることができます。最初の方法はアロー関数、2 番目の方法はコンポーネントメソッドです。
$emit () に渡される追加の引数はすべてリスナーに直接渡されます。例えば、$emit ('foo', 1, 2, 3) がトリガーされると、リスナー関数はこれら 3 つの引数を受け取ります。
そして、3 つの引数を使用して渡されたコールバックを受け取ることができます。
- 現在、イベントは click によってのみトリガーされるように制限したいのですが、条件を JavaScript で判断し、満たされた場合にのみこのイベントをトリガーするにはどうすればよいですか?
子コンポーネント内で defineEmits () を定義して、トリガーしたいイベントを宣言し、その後 emit を使用してトリガーできます。
<script setup>
const emit =defineEmits(['inFouse','submit'])
function buttonClick(){
emit('submit')
}
</script>
- OK、基本的にはすべて説明しました。Vue のテンプレート内でトリガーするには
@click='$emit('名前',パラメータ)'
、そして defineEmit 後に emit (' 名前 ') は JS でトリガーすることになります。
2.3 Props コンポーネントデータの受け渡し#
Props は親コンポーネントから子コンポーネントにデータを渡すための解決策です。その役割は、受け入れる props を明示的に宣言することです。
- props を渡すにはどうすればよいですか?
まず、子コンポーネント内で宣言する必要があります。つまり、どのデータを受け入れる必要があるかを伝えます。宣言は配列の形式でもオブジェクトの形式でも行えます。
<script setup>
const props = defineProps(['foo'])
const props = defineProps({
title: String,
likes: Number
})
console.log(props.foo)
</script>
親コンポーネントがデータを渡したい場合は:
<BlogPost title="私のVueとの旅" likes="2"/>
<BlogPost title="Vueでのブログ" likes="2" />
<BlogPost title="なぜVueは楽しいのか" likes="2" />
- 渡すデータの値は動的にできますか?つまり、親コンポーネントが与える値が変化する場合です。
<!-- 変数の値に基づいて動的に渡す -->
<BlogPost :title="post.title" />
<!-- より複雑な式の値に基づいて動的に渡す -->
<BlogPost :title="post.title + ' by ' + post.author.name" />
この方法を使用すると、動的な値を渡すことができ、その値が変化すると子コンポーネントも変化します。
3. 異なるタイプの値を渡すことができます。渡す値は number、boolean、array などですが、文法に基づいて時には直感に反することがあります。
```vue
Number 型の値を渡す
<!-- 変数の値に基づいて動的に渡す -->
<BlogPost :likes="post.likes" />
boolean値を渡す
<!-- propを記述するだけで値を渡さないと、暗黙的に`true`に変換されます -->
<BlogPost is-published />
<!-- `false`は静的な値ですが、v-bindを使用する必要があります -->
<!-- これはJavaScriptの式であり、文字列ではありません -->
<BlogPost :is-published="false" />
<!-- 変数の値に基づいて動的に渡す -->
<BlogPost :is-published="post.isPublished" />
Array値を渡す
<!-- この配列は定数ですが、v-bindを使用する必要があります -->
<!-- これはJavaScriptの式であり、文字列ではありません -->
<BlogPost :comment-ids="[234, 266, 273]" />
<!-- 変数の値に基づいて動的に渡す -->
<BlogPost :comment-ids="post.commentIds" />
Object値を渡す
<!-- このオブジェクトリテラルは定数ですが、v-bindを使用する必要があります -->
<!-- これはJavaScriptの式であり、文字列ではありません -->
<BlogPost
:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
/>
<!-- 変数の値に基づいて動的に渡す -->
<BlogPost :author="post.author" />
```
簡単に言えば、値を渡す場合、文字列を表現したい場合はpropsの属性を使用し、式を表現したい場合は:propsの属性を使用します。
4. そして props は一方向のデータフローであり、親コンポーネントから子コンポーネントにデータを渡すことができ、子コンポーネントは props を通じて親コンポーネントにデータを渡すことはできません。
しかし、多くの場合、props のデータを変更したいと思います。例えば、props の局所データの状況を取得したい、またはprops のデータを変換したい場合です。
2.4 v-model コンポーネントデータの受け渡し#
v-model は構文糖であり、双方向バインディングをより便利に実現できます。
- v-model の使用方法
<!-- Child.vue -->
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>親がバインドしたv-modelは: {{ model }}</div>
</template>
<!-- Parent.vue -->
<Child v-model="count" />
defineModel () が返す値は ref です。これは他の ref と同様にアクセスおよび変更できますが、親コンポーネントと現在の変数間の双方向バインディングの役割を果たします:
その.value と親コンポーネントの v-model の値は同期します;
子コンポーネントで変更されると、親コンポーネントにバインドされた値も更新されます。
2. v-model は引数を受け取ります。
親コンポーネント上の v-model も引数を受け取ることができます:
<UserName
v-model:first-name="first"
v-model:last-name="last"/>
<MyComponent v-model:title="bookTitle" />
子コンポーネント内では、文字列を最初の引数としてdefineModel()に渡すことで、対応する引数をサポートできます:
<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>
<template>
<input type="text" v-model="title" />
</template>
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>
<template>
<input type="text" v-model="firstName" />
<input type="text" v-model="lastName" />
</template>
- v-model 修飾子
- .lazy
デフォルトでは、v-model は各 input イベント後にデータを更新します(IME の入力段階の状態を除く)。lazy 修飾子を追加すると、各 change イベント後にデータを更新するように変更できます:
<!-- "input"ではなく"change"イベント後に同期更新 -->
<input v-model.lazy="msg" />
- .number
ユーザーの入力を自動的に数値に変換したい場合は、v-model の後に.number 修飾子を追加して入力を管理できます:
<input v-model.number="age" />
その値が parseFloat () で処理できない場合、元の値が返されます。number 修飾子は、入力ボックスに type="number" がある場合に自動的に有効になります。
3. .trim
ユーザーの入力の前後の空白文字を自動的にフィルタリングしたい場合は、v-model に trim 修飾子を追加できます:
vue <input v-model.trim="msg" />
2.5 属性の透過#
-
属性の継承
属性の透過は、親コンポーネントの属性を子コンポーネントに渡すことを指します。この属性がprops や emitsとして宣言されていない場合、その属性は子コンポーネントに渡されます。<Child id="foo" class="bar" />
最も一般的な例は class、style、id です。コンポーネントが単一の要素をルートとしてレンダリングする場合、透過された属性は自動的にルート要素に追加されます。例えば、コンポーネントがあり、そのテンプレートが次のようになっているとします:
<!-- <MyButton> のテンプレート --> <button>クリックしてください</button> 親コンポーネントがこのコンポーネントを使用し、classを渡した場合: <MyButton class="large" /> 最後にレンダリングされるDOM結果は: <button class="large">クリックしてください</button>
簡単に言えば、コンポーネント外に追加された属性が props でも emits でもない場合、その属性は自動的にコンポーネント内の最外層データに読み込まれます。
一般的には class や style の統合に使用されます。外側に class を書いた場合、それも内部に統合されます。 -
v-on リスナーの基本、つまりコンポーネントにイベントリスナーを追加し、コンポーネント内部でそのイベントをトリガーすることができます。
<Child v-on:custom-event="handleCustomEvent" />
click リスナーは
<Child>
のルート要素、つまりその原生の<button>
要素に追加されます。原生の<button>
がクリックされると、親コンポーネントの onClick メソッドがトリガーされます。
同様に、原生のbutton
要素自身も v-on を通じてイベントリスナーをバインドしている場合、そのリスナーと親コンポーネントから継承されたリスナーの両方がトリガーされます。
したがって、このリスニングは子コンポーネントと親コンポーネント間の接続を実現できます。 -
透過は連続性を持ちます
つまり、A が B に渡し、B が C に渡すことができます。