Vue Fallthrough属性
1. Fallthrough属性(フォールスルー属性)とは
Vue では、プロップス(Props) として宣言されていない属性(Attribute)を使用してコンポーネントを呼び出すことができ、それらの属性はコンポーネント内の ルート要素(Root element) にそのまま引き継がれます。これを Fallthrough属性(フォールスルー属性) と呼びます。
Fallthrough属性を活用することで、コンポーネントが作成される親側から全体の構造を把握しやすくなり、属性をいちいちプロップスとして宣言する必要がなくなるため、コードが大幅に簡素化されます。
一般的に Fallthrough される属性には、class、style、そして v-on によるイベントリスナーなどが含まれます。
2. Fallthrough属性の活用
例えば、コンポーネント内部にスタイルを隠蔽してしまうのではなく、親側からコンポーネントのスタイリングを制御したい場合に非常に便利です。
ここでは、Vue で基本的な「Todoリスト」を作成し、style 属性がどのように各タスクを表すコンポーネントに継承されるかを見ていきましょう。
App.vue には、タスクのリスト、新しいタスクを追加するための <input> 要素、およびボタンが含まれます。リストの各項目は <todo-item /> コンポーネントです。
2.1 App.vue の構成
<template>
<h3>Todoリスト</h3>
<ul>
<todo-item
v-for="x in items"
:key="x"
:item-name="x"
/>
</ul>
<input v-model="newItem">
<button @click="addItem">追加</button>
</template>
<script>
export default {
data() {
return {
newItem: '',
items: ['リンゴを買う', 'ピザを作る', '芝を刈る']
};
},
methods: {
addItem() {
this.items.push(this.newItem);
this.newItem = '';
}
}
}
</script>2.2 TodoItem.vue の構成
TodoItem.vue は、実行するタスクの説明をプロップスとして受け取るだけのシンプルな構成です。
<template>
<li>{{ itemName }}</li>
</template>
<script>
export default {
props: ['itemName']
}
</script>2.3 main.js のセットアップ
アプリケーションを正しく動作させるために、main.js でコンポーネントを登録します。
import { createApp } from 'vue'
import App from './App.vue'
import TodoItem from './components/TodoItem.vue'
const app = createApp(App)
app.component('todo-item', TodoItem)
app.mount('#app')3. スタイルの継承を確認する
属性がコンポーネントの <template> 内にあるルート要素へと継承されることを確認するために、App.vue からリストアイテムにスタイルを適用してみます。
3.1 実装例:親からスタイルを渡す
App.vue 内で、コンポーネントに直接 style を記述します。
<template>
<h3>Todoリスト</h3>
<ul>
<todo-item
v-for="x in items"
:key="x"
:item-name="x"
style="background-color: lightgreen;"
/>
</ul>
<input v-model="newItem">
<button @click="addItem">追加</button>
</template>この状態でブラウザを開き、リストの <li> 要素を右クリックして「検証(Inspect)」を選択してみてください。style 属性が実際に <li> 要素に適用されていることが確認できるはずです。
4. 'class' および 'style' 属性のマージ
もしコンポーネント自体にすでに class や style が設定されており、さらに親からも Fallthrough 属性としてこれらが渡された場合、Vue はそれらの属性を自動的に マージ(結合) します。
4.1 実装例:スタイルのマージ
親からのスタイルに加え、TodoItem.vue コンポーネント内部で <li> 要素にマージン(余白)を追加してみましょう。
TodoItem.vue:
<template>
<li style="margin: 5px 0;">{{ itemName }}</li>
</template>
<script>
export default {
props: ['itemName']
}
</script>ブラウザで要素を検証すると、属性がマージされていることがわかります。コンポーネント内で直接設定された margin と、親から継承された background-color が一つの style 属性として統合されます。
5. $attrs による継承先の指定
コンポーネントにルートレベルの要素が複数存在する場合(マルチルートコンポーネント)、Vue はどの要素に属性を継承させるべきか判断できません。
特定の要素に Fallthrough 属性を適用したい場合は、組み込みオブジェクトである $attrs を使用して対象の要素をマークします。
5.1 実装例:$attrs を使用した明示的な継承
TodoItem.vue:
<template>
<div class="pinkBall"></div>
<li v-bind="$attrs">{{ itemName }}</li>
<div class="pinkBall"></div>
</template>このように v-bind="$attrs" を記述することで、親から渡されたプロップス以外のすべての属性を指定した要素(この場合は <li>)へ確実に届けることができます。