Vue 中的 inheritAttrs 和 $attrs

inheritAttrs 是组件的一个属性,有 true 和 false 两个值。默认情况下 vue 会把父作用域的不被认作 props 的特性绑定且作为普通的 HTML 特性应用在子组件的根元素上,例如:

<div id="app">
    <children-component :name="name" :age="age"></children-component>
</div>
var vm = new Vue({
    el: "#app",
    data: {
        name: "juliet",
        age: 23
    },
    components: {
        "chilren-component": {
            props: ["name"],
            template: `<div>{{ name }}</div>`
        }
    }
})

而最终渲染出来是下面这样:

<div id="app">
	<div age="23">juliet</div>
</div>

age 被当作子组件根元素上的属性了,而在某些特定场景下为我们不希望出现这种情况,那么可以在子组件中加上 inheritAtrrs = false 属性,如下所示:

var vm = new Vue({
    el: "#app",
    data: {
        name: "juliet",
        age: 23
    },
    components: {
        "chilren-component": {
            props: ["name"],
            inheritAttrs: false,
            template: `<div>{{ name }}</div>`
        }
    }
})

这样最终渲染出来是下面这样的:

<div id="app">
	<div>juliet</div>
</div>

age 不再被渲染为子组件根元素上的属性了,那要怎么获得 age 的值呢,这时就可以用 $attrs 来获取了:

var vm = new Vue({
    el: "#app",
    data: {
        name: "juliet",
        age: 23
    },
    components: {
        "chilren-component": {
            props: ["name"],
            inheritAttrs: false,
            template: `
                  <div>
                        <div>{{ name }}</div>
                        <div>{{ $attrs.age }}</div>
                  </div>
            `
        }
    }
})

最终渲染出来的是下面这样的:

<div id="app">
    <div>
        <div>juliet</div>
        <div>23</div>
    </div>
</div>

所以 $attrs 是包含了在父组件中除了注册在 props 中的其余属性的对象。它还有另外一个作用,假设现在有父子孙三个组件,如果想让父组件传值给孙组件该怎么办,常规办法就是利用 props 一级一级的往下传递,如下所示:

<div id="app">
    <children-component :name="name" :age="age"></children-component>
</div>
var vm = new Vue({
    el: "#app",
    data: {
        name: "juliet",
        age: 23
    },
    components: {
        "children-component": {
            props: ["name", "age"],
            template: `
                  <div>
                        <div>{{ name }}</div>
                        <grand-component :age="age"></grand-component>
                  </div>
            `,
            components: {
                "grand-component": {
                    props: ["age"],
                    template: `
                        <div>{{ age }}</div>
                    `
                }
            }
        }
    }
})

最终渲染出来的效果如下:

<div id="app">
    <div>
        <div>juliet</div>
        <div>23</div>
    </div>
</div>

虽然达到了最终的效果,但是子组件并没有使用到 age 的值,但由于孙组件要使用 age,所以它不得不接收父组件传过来的 age 并且将其传给孙组件。现在只有 3 层组件,如果有 5 层甚至十几层呢,得写很多多余的 props 和 attribute 来传递值。但是使用 $attrs 就不用这么麻烦,如下所示,HTML 代码和上面相同,javascript代码不同:

var vm = new Vue({
    el: "#app",
    data: {
        name: "juliet",
        age: 23
    },
    components: {
        "children-component": {
            props: ["name"],
            template: `
                  <div>
                        <div>{{ name }}</div>
                        <grand-component v-bind="$attrs"></grand-component>
                  </div>
            `,
            inheritAttrs: false,
            components: {
                "grand-component": {
                    template: `
                        <div>{{ $attrs.age }}</div>
                    `,
                    inheritAttrs: false
                }
            }
        }
    }
})

渲染出来的和上面的结果一模一样,但是因为 age 属性是传给孙组件的,子组件的 props 中就不需要传 age 属性了,而是直接通过 v-bind="$attrs" 传给孙组件即可。

这里需要注意的是,inheritAttrs: false 不会影响 style 和 class 的绑定,也就是说在父组件对子组件的 style 和 class 属性进行了设置,那么即使子组件设置了 inheritAttrs: false,这两个属性还是会合并到子组件的根元素上。

posted @ 2021-02-08 12:01  LittleJuliet  阅读(406)  评论(0编辑  收藏  举报