Vue3中attrs突然变多或消失?别慌,教你从原理到避坑全搞定
最近在做Vue3的后台组件库重构时,碰到了个挺头疼的事:之前用Vue2封装的面包屑、输入框这类“传递层”组件,移到Vue3后要么绑定的原生属性没传到DOM上,要么子组件自己暴露的props也混进了attrs里,折腾了两天才理清楚,后来翻了不少资料,和组里的前端老炮儿聊了聊,才明白Vue3对attrs的底层逻辑做了不小的调整,踩坑大多是没跟上这些变化,今天就用大家听得懂的话,把Vue3 attrs的来龙去脉、核心用法、常见坑点和避坑技巧说透。
先搞懂Vue3里的attrs到底是什么?和Vue2有啥本质区别?
很多刚转Vue3的同学可能会说“不就是没在props里定义的属性嘛,Vue2就有啊”——这只说对了一半,甚至一小半。
先回忆下Vue2的attrs:它只存未声明的普通属性(不包括style、class),style和class是单独处理的,会自动合并到根元素上;默认是自动透传到子组件的根DOM元素上,不管你有没有显式调用;在有单一根元素的组件里,如果你用了inheritAttrs: false,需要手动用v-bind="$attrs"绑定剩下的元素,但注意这时候style和class还是会自动透传根元素,除非你改子组件模板。
那Vue3呢?改动可以说是“重构级”的,分三个核心点: 第一,属性范围扩大了:attrs现在存的是所有未被props、emits、expose显式“认领”的东西——包括普通属性、style、class、原生事件(click、@input)、slot默认值之外的自定义事件!是不是很意外?Vue2的自定义事件如果没在子组件emit声明,是不会在$attrs里的,只能用$listeners单独处理,但Vue3把$listeners完全合并到attrs里了,这是最大的变化之一。 第二,透传规则变宽松了,但前提是得有条件:之前Vue2透传只看有没有单一根元素,现在Vue3支持多根元素+显式透传绑定,但如果子组件还是单一根元素,inheritAttrs默认还是true,自动透传所有未声明的属性(包括合并后的style、class、事件)到这个根元素;如果是多根元素,inheritAttrs自动失效,必须手动用v-bind="$attrs"绑定到你想传的某个元素上,不然Vue3会在控制台给你个小警告——这也是很多同学碰到“变多”“消失”的触发场景之一。 第三,在setup里的获取方式不一样了:Vue2是this.$attrs,Vue3组合式API里要从上下文context里解构attrs,或者用useAttrs这个钩子函数,而且这里拿到的attrs是响应式的浅层代理——注意是浅层,也就是说如果attrs里有个对象或数组,修改它的内部属性是不会触发视图更新的,但如果直接替换整个对象数组,就会,这个浅层响应式的设计也藏着个小坑,后面会说。
哦对了,还有个细节可能很多人没注意:在
code前端网