フォールスルー属性
このページは、すでにコンポーネントの基礎を読んでいることを前提にしています。初めてコンポーネントに触れる方は、まずそちらをお読みください。
属性の継承
"フォールスルー属性"とは、あるコンポーネントに渡されたものの、受け取ったコンポーネントの props や emits で明確に宣言されていない属性、または v-on イベントリスナーを指します。よくある例としては、class、style、id 属性などがあります。
コンポーネントが単一のルート要素をレンダリングする時、フォールスルー属性は自動的にルート要素の属性に追加されます。例えば、次のようなテンプレートを持つ <MyButton> コンポーネントがあったとします:
template
<!-- <MyButton> のテンプレート -->
<button>Click Me</button>そして、このコンポーネントを使う親が以下です:
template
<MyButton class="large" />最終的に DOM は以下のようにレンダリングされます:
html
<button class="large">Click Me</button>ここで、<MyButton> は class を受け入れ可能な props として宣言していません。そのため、class はフォールスルー属性として扱われ、自動的に <MyButton> のルート要素に追加されます。
class と style のマージ
もし、子コンポーネントのルート要素にすでに class や style 属性がある場合は、親から継承された class や style の値にマージされます。先ほどの例の <MyButton> のテンプレートを次のように変更するとします:
template
<!-- <MyButton> の テンプレート -->
<button class="btn">Click Me</button>そうすると、最終的にレンダリングされる DOM は、こうなります:
html
<button class="btn large">Click Me</button>v-on リスナーの継承
同じルールが v-on イベントリスナーにも適用されます:
template
<MyButton @click="onClick" />click リスナーは <MyButton> のルート要素、つまりネイティブの <button> 要素に追加されます。ネイティブの <button> がクリックされた時、親コンポーネントの onClick メソッドがトリガーされます。もし、ネイティブの <button> が既に v-on でバインドされた click リスナーを持っている場合、両方のリスナーがトリガーされます。
ネストされたコンポーネントの継承
あるコンポーネントが他の 1 つのコンポーネントをルートノードとしてレンダリングする場合を考えてみましょう。例として、<MyButton> をルートとして <BaseButton> をレンダリングするようにリファクタリングしました:
template
<!-- シンプルに他の 1 つのコンポーネントをレンダリングする <MyButton/> のテンプレート -->
<BaseButton />この時、<MyButton> が受け取ったフォールスルー属性は、自動的に <BaseButton> に転送されます。
以下の点に注意してください:
転送された属性には、
<MyButton>が props として宣言した属性や、宣言したイベントのv-onリスナーは含まれません。言い換えると、宣言した props とリスナーは<MyButton>によって "消費" されています。転送された属性は、
<BaseButton>が宣言していれば、props として受け取ることができます。
属性の継承の無効化
コンポーネントに自動的な属性の継承をさせたくない場合は、コンポーネントのオプションで inheritAttrs: false を設定できます。
3.3 以降では、<script setup> で直接 defineOptions を使用することもできます:
vue
<script setup>
defineOptions({
inheritAttrs: false
})
// セットアップのロジック
</script>属性の継承を無効にする一般的なシナリオは、ルートノード以外の要素に属性を適用する必要がある場合です。 inheritAttrs オプションを false に設定することで、フォールスルー属性を適用する場所を完全に制御できます。
これらのフォールスルー属性は、テンプレート内の式で $attrs として直接アクセスできます:
template
<span>Fallthrough attributes: {{ $attrs }}</span>$attrs オブジェクトには、コンポーネントの props や emits オプションで宣言されていないすべての属性(例えば class, style, v-on リスナーなど)が含まれます。
備考:
props とは異なり、フォールスルー属性は JavaScript では元のケーシングを保持します。したがって、
foo-barのような属性は$attrs['foo-bar']としてアクセスされる必要があります。@clickのようなv-onイベントリスナーは、オブジェクトで$attrs.onClickという関数として公開されます。
前のセクションで紹介した <MyButton> コンポーネントの例では、スタイリングのために実際の <button> 要素を <div> でラップする必要がある場合があります:
template
<div class="btn-wrapper">
<button class="btn">Click Me</button>
</div>class や v-on リスナーなどのすべてのフォールスルー属性を、外側の <div> ではなく、内側の <button> に適用されるようにしたいです。これは、 inheritAttrs: false と v-bind="$attrs" で実現できます:
template
<div class="btn-wrapper">
<button class="btn" v-bind="$attrs">Click Me</button>
</div>引数なしの v-bind はオブジェクトのすべてのプロパティをターゲット要素の属性としてバインドすることを覚えておきましょう。
複数のルートノードでの属性継承
ルートノードが 1 つのコンポーネントと異なり、複数のルートノードを持つコンポーネントは、自動的に属性をフォールスルーするふるまいがありません。 $attrs が明示的にバインドされていない場合は、実行時に警告が出ます。
template
<CustomLayout id="custom-layout" @click="changeValue" />もし <CustomLayout> が以下のようなマルチルートのテンプレートを持っている場合、 Vue はどこにフォールスルー属性を適用すればよいか分からないため、警告されます:
template
<header>...</header>
<main>...</main>
<footer>...</footer>警告は $attrs が明示的にバインドされている場合は抑制されます:
template
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>JavaScript 内でフォールスルー属性にアクセスする
必要であれば、<script setup> 内で useAttrs() API を使用してコンポーネントのフォールスルー属性にアクセスできます:
vue
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>もし <script setup> を使用していない場合、 attrs は setup() コンテキストのプロパティとして公開されます:
js
export default {
setup(props, ctx) {
// フォールスルー属性が ctx.attrs として公開される
console.log(ctx.attrs)
}
}ここで attrs オブジェクトは常に最新のフォールスルー属性を反映していますが、リアクティブではないことに注意してください(パフォーマンス上の理由です)。ウォッチャーを使ってその変更を監視することはできません。リアクティビティーが必要であれば、 props を使ってください。または、 onUpdated() を使用して、更新されるたびに最新の attrs による副作用を実行することもできます。