關於 Vue3 Setup X Attrs 傳入 props 行為的小坑
你以為的 V-bind="$attrs" 真的是你以為的那樣嗎?要不要點開我瞧瞧?
背景該要
公司近期在落實一項措施:包裝 element UI 組件以暴露內部共用方法,並重新命名為公司限定組件。
在開發功能 Monorepo 的過程發現 el-upload 組件從外部傳入 before-remove 方法後卻沒有被觸發,進入文件查看也確實透過 V-bind="$attrs" 將 props 全開了,跟兩三個同事討論許久都認為這個理解合理,那麼是哪裡出了問題呢?
打包 Upload 文件
1 | <script setup> |
語法糖 Vue Attrs
$attrs 是方便組件傳遞的時候「門戶大開」,你敢傳我就敢收!定義可以參考Vue 官方文件
所以這次的困難點在於自己的思想爭鬥上:明明已經全開了卻還是收不到,究竟卡在哪?
官方解釋
“透传 attribute”指的是传递给一个组件,却没有被该组件声明为
props或emits的 attribute 或者v-on事件监听器。
ChatGpt
Attrs 適用傳遞未聲明的 props
$attrs不是應該會對外層傳入的props照單全收?
在 Vue 2 Composition API(或 Vue 3)中,
$attrs確實應該會自動接收所有未定義為props的外部屬性,但有幾種情況可能影響其行為:
attrs 的正常行為
如果父元件傳入了一些 props,但子元件 沒有明確定義 這些 props,這些屬性會自動被放入 $attrs,並且可以通過 v-bind="$attrs" 傳遞給內部元素:
1 | <!-- Parent.vue --> |
在這裡,因為 custom-attr 不是 props,所以它會自動被放入 $attrs。
inheritAttrs: false 影響 $attrs
Vue 2.7+ 和 Vue 3 提供了 inheritAttrs: false,當設定為 false 時:
$attrs仍然存在,但不會自動綁定到最外層元素。- 你需要手動用
v-bind="$attrs"綁定到某個子元素。
如果你沒有 inheritAttrs: false,Vue 會自動把 attrs 綁定到最外層元素。
props 會影響 $attrs
如果子元件 有定義相應的 props ,那麼這些 props 不會進入 $attrs ,因為它們已經被 Vue 處理為 props。
這是因為
v-bind="$attrs"只會綁定「非 props 屬性」,而 before-remove 是 Upload 元件的props,所以不會自動進入 $attrs。
但 Element Plus 的
<Upload>元件明確定義了before-remove為props,因此 Vue 不會把它放進$attrs。
以下範例的 defined-prop 被定義在 props 陣列中,會造成該 attribute 不被自動放進 $attrs,而被定義在 props 中:
1 | <!-- Parent.vue --> |
這一點恰恰就是本次遇到的「有定義相應的 props ,那麼這些 props **不會進入 $attrs**」,也就是說需要手動將被定義相應的 props 給綁定上 <Upload></Upload>。
為什麼 $attrs 不包含 props?
在 Vue 2 / Vue 3 中,$attrs 只會收集「未在 props 定義的屬性」,例如:
1 | export default { |
這意味著:
props.autoUpload、props.accept、props.drag不會進$attrs。但 任何其他非
props的 HTML 屬性(例如 class、id、data-*)會進$attrs。
v-bind=”$attrs” 只適用於 HTML 屬性
如果 $attrs 包含的屬性是事件(例如 @click),它只會綁定到 能夠接收事件的標籤 。
1 | <template> |
這樣 $attrs 中的 onClick 事件才能被 <button> 接收。
但如果 $attrs 綁定在 <div> 上,某些事件可能不會生效,因為 div 本身不處理某些特定的事件類型。
setup 語法糖
是否在 template 裡撰寫 可以省略
props
在 Vue 2 Composition API(Vue 2.7+ 或使用 @vue/composition-api)和 Vue 3 中,你不能在
<template>直接使用props而不在setup()明確定義。
目前使用的是
<script setup>
在 Vue 3
<script setup>語法 中,props 可以直接在<template>使用,不需要手動return,因為 **Vue 會自動解包props**!✅
props 可以直接在 <template> 使用
不需要手動 return,因為 defineProps() 會自動讓 props 在 <template> 可用。
這是 <script setup> 的特性,和 Options API、普通 Composition API 不同。
1 | <script setup> |
以上是這次學習到的兩個應注意而未注意的重要小細節!!!
- 未明確為
defineProps定義的對象,才能為$attrs所捕捉! <script setup>已經直接將 props 解包!可以直接使用而不需要props.attr。