Skip to content

Vue 3 實戰:掌握透傳屬性(Fallthrough Attributes)與 $attrs 的靈活運用

Vue 3 透傳屬性:$attrs 與 useAttrs

在開發 Vue 元件時,我們常會遇到這種情況:父元件傳入了一些屬性(如 classiddisabled@click),但子元件並沒有透過 definePropsdefineEmits 宣告它們。這些 未被宣告 的屬性就會變成 透傳屬性(Fallthrough Attributes),也就是 attrs

預設情況下,Vue 會自動將這些屬性掛載到子元件的根元素(Root Element)上。

什麼是透傳屬性?

讓我們透過一個實戰範例來區分 props 與 attrs:

上(父)層

html
<MyButton class="primary" id="submit-btn" disabled text="送出" />

下(子)層

js
defineProps({
  text: {
    type: String,
    required: true,
    default: 'button',
  },
});

解析結果:

  • text: 因為有在 defineProps 宣告,它是 props
  • classiddisabled: 未被宣告,它們被歸類為 Attributes($attrs,並自動加在子元件的根元素上。

class 與 style 是合併,不是覆蓋

透傳進來的 classstyle 會與根元素上原有的值合併;其餘同名屬性則以父層傳入的為準。

多根節點元件不會自動透傳

根節點超過一個時,Vue 無法判斷屬性該掛到哪裡,會直接跳過並發出警告。此時必須在目標元素上手動寫 v-bind="$attrs"

進階控制:關閉自動透傳

有時候我們不希望 Vue 自動將屬性亂塞到根元素(例如:根元素只是一個包裝層),這時可以透過 defineOptions 來關閉這個行為:

js
defineOptions({
  inheritAttrs: false,
});

核心觀念

inheritAttrs 設定為 false 後:

  • 屬性就不會自動加到元件的根元素上。
  • 開發者必須手動決定這些屬性($attrs)要放在哪裡,實現更精準的 UI 控制。

如何手動取得並分配 $attrs

當您關閉自動透傳後,可以透過以下兩種方式取得這些被遺忘的屬性:

在 Template 中直接使用 $attrs

這在想要將屬性轉發給內部特定元素時非常實用:

html
<p>{{ $attrs }}</p>

在 Script 中使用 useAttrs()

如果您需要在邏輯中處理這些屬性,可以使用 Composition API:

vue
<script setup>
import { useAttrs } from "vue";

const attrs = useAttrs();

// 您可以觀察到所有的透傳屬性
console.log(attrs);
console.log(attrs.class);
console.log(attrs.id);
</script>

<template>
  <ThroughIn v-bind="attrs" />
</template>

特殊應用:透過 $attrs 向外傳遞事件

透傳屬性不僅包含資料,也包含 事件監聽器。若要在自定義元件內手動觸發父層傳來的點擊事件,必須注意命名方式(需使用 on 開頭):

html
<input type="button" value="Out 按鈕" @click="$attrs.onClick">

或是直接使用 v-bind 將所有屬性與事件一次性轉發給內層元件:

html
<InnerComponent v-bind="attrs" />

總結

掌握透傳屬性是封裝高品質 UI 元件(如 Button、Input)的必經之路。透過 inheritAttrs: false$attrs 的配合,您能確保元件的 HTML 結構乾淨,同時保有父元件傳入樣式與事件的靈活性。

常見問題

什麼是透傳屬性?

父元件傳給子元件、但子元件沒有用 definePropsdefineEmits 宣告的屬性與事件監聽器,就是透傳屬性。預設情況下 Vue 會把它們自動加到子元件的根元素上。

透傳的 class 與 style 會覆蓋原本的嗎?

不會,classstyle 會與元件根元素上原有的值合併,其餘同名屬性則以父層傳入的為準。

什麼時候要關閉 inheritAttrs?

當根元素只是外層包裝、真正該接收屬性的是內部元素時,例如:自訂輸入框的外框是 <div>、實際欄位是 <input>。此時關閉自動透傳,再用 v-bindattrs 綁到 <input> 上。

多根節點的元件會自動透傳嗎?

不會,因為 Vue 無法判斷該掛到哪一個節點,還會發出警告。必須在目標元素上手動寫 v-bind="$attrs"

$attrs 與 useAttrs() 差在哪裡?

$attrs 是在模板中直接可用的變數,useAttrs() 則是在 <script setup> 中取得同一份資料的方式,適合需要在邏輯中判斷或加工屬性時使用。

事件也算在透傳屬性裡嗎?

算。父層寫的 @click 會以 onClick 的形式出現在 attrs 中,因此可以用 v-bind 一次轉發,或單獨取出 $attrs.onClick 綁到指定元素上。

延伸閱讀