• $attrs 属性解释:包含了父作用域中不作为组件 props 或自定义事件的 attribute 绑定和事件。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定,并且可以通过 v-bind="$attrs" 传入内部组件 —— 这在创建高阶的组件时会非常有用。
  • inheritAttrs 属性解释:如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false

可能不是很好理解,我们可以举个例子来验证一下。

# 在父组件 app.vue 中

<template>
  <div>
    <MyInput type="text" placeholder="输入用户名" v-model="state.text" />
    <MyInput type="password" placeholder="输入密码"  v-model="state.pass"  />
  </div>
</template>
<script setup>
import MyInput from "@/components/myInput.vue";
import { reactive } from "vue";
const state = reactive({
  text: "",
  pass: "",
});
</script>

# 子组件 myInput.vue 设置 inheritAttrs: true(默认)

<template>
  <div class="input">
    <input v-bind="$attrs" v-model="modelValue" />
  </div>
</template>
<script>
export default {
  props: {
    modelValue: [String, Number],
  },
};
</script>

img

# 子组件 myInput.vue 设置 inheritAttrs: false

<template>
  <div class="input">
    <input v-bind="$attrs" v-model="modelValue"/>
  </div>
</template>
<script>
export default {
  inheritAttrs: false,
  props: {
    modelValue: [String, Number],
  },
};
</script>

img

小结:

由上述例子可以看出,子组件的 props 中未注册父组件传递过来的属性。

  • 当设置 inheritAttrs:true 时,子组件的顶层标签元素中会渲染出父组件传递过来的属性 (例如:type="text" 等)
  • 当设置 inheritAttrs: false 时,子组件的顶层标签元素中不会渲染出父组件传递过来的属性
  • 不管 inheritAttrs 为 true 或者 false,子组件中都能通过 $attrs 属性获取到父组件中传递过来的属性。

# $attrs 和 inheritAttrs 实例

官网的文档简短而又不清晰,实在是看不懂,只好自己找代码验证来看看是什么意思:

<!DOCTYPE html>
<html lang="en">
  
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js"></script>
</head>
  
<body>
    <div id="app">
        <father :v1="'value1'" :v2="'value2'" :v3="'value3'"></father>
    </div>
</body>
  
</html>
<script>
const app = Vue.createApp({
    data() {
        return {}
    },
})
app.component('father', {
 // inheritAttrs: false,
    props: ['v1'],
    template: ` <div><p>v1 is </p>
          <son v-bind='$attrs' :some="1"></son>
           </div>`,
    created() {
        console.log('father:', this.$attrs)
    }
})
app.component('son', {
    // inheritAttrs: false,
    props: ['v2'],
    template: `<div><p>v2 is </p>
                     <grandSon v-bind='$attrs'></grandSon>
              </div>`,
    created() {
        console.log('son:', this.$attrs)
    }
})
app.component('grandSon', {
    props: ['v3'],
    template: `<p>v3 is </p>`,
    created() {
        console.log('grandSon:', this.$attrs)
    }
})
app.mount('#app')
</script>

页面显示的结果:

v1 is value1

v2 is value2

v3 is value3

页面源代码:

<div id="app" data-v-app="">
   <div v2="value2" v3="value3"> <!-- 这是 father -->
      <p>v1 is value1</p>
      <div v3="value3" some="1">  <!-- 这是 son-->
          <p>v2 is value2</p>
           <p some="1">v3 is value3</p>  <!-- 这是 grandSon -->
      </div>
   </div>
</div>

控制台打印是当前组件的 $attrs:

father: Proxy

son: Proxy

grandSon: Proxy

首选,father 组件被传入了 3 个值,但是实际使用 props 接收的只有 v1,v2 和 v3 作为 attributes 在 DOM 里面渲染了。

img

上图的 devtool 也可以说明,另外就是控制台也同时证明了。

同样 son 组件只是接收 v2 作为 prop:

img

grandSon 组件只是接收 v3 作为 prop

img

father prop:v1,attributes: v2,v3

son prop:v2 ,attributes:v3,some

grandSon prop:v3,,attributes: some

发现无论是 father 传入的 3 个值 v1,v2,v3 还是 son 又传入的值 ':some=1',

只要不被 prop 传入下一层组件,那么一定是在下一层组件的 $attrs,也就是说不被作为 prop 的值会传入下一个组件作为 attrs 的一员。一个组件的 attrs 由父组件传递以及自己自带的组合而成。

上面说的是 $attrs, 那么 inheritAttrs 则说的是 attrs 继承,这里的继承是控制 DOM 渲染,不继承也就是不渲染了,但是实际还是存在这个 attrs 的。

inheritAttrs 属性默认是 true, 所以能看到上面的结论,attrs 会往下传,当设置为 false 的时候就不会在 DOM 渲染从上一层继承来的 attrs。

修改一下代码:

app.component('father', {
   inheritAttrs: false,    // 不继承
    props: ['v1'],
    template: ` <div><p>v1 is </p>
          <son v-bind='$attrs' :some="1"></son>
           </div>`,
    created() {
        console.log('father:', this.$attrs)
    }
})

father 组件这不继承 attrs,控制台的打印没变:

father: Proxy

son: Proxy

grandSon: Proxy

devtool 这里依然可以看到 attrs

img

但是看源代码:

<div id="app" data-v-app="">
  <div>                          <!-- 这里是 father --> <!-- 看这行 -->
    <p>v1 is value1</p>
    <div v3="value3" some="1">     <!-- 这里是 son-->
      <p>v2 is value2</p>
      <p some="1">v3 is value3</p>   <!-- 这里是 grandSon-->
      </div>
    </div>
</div>

DOM 渲染里面的 v2,v3 attrs 都不存在了。

所以综合总结一下:

  • $attrs 就是给组件传值排除了作为 prop 的那部分 (比如 father 的 v2,v3),包括了 (class,id)
  • inheritAttrs 只是用来控制 attrs 是否在 DOM 中渲染。