Vue 组件通信方式之一 inject和provide

114 阅读2分钟

使用方法

在父组件中声明传递给子组件及后代的provide属性,provide可以是一个对象,或者返回对象

provide () {
        return {
            father_string: this.father_string
        }
}

优点

这个方法不局限于父子组件,可隔代传递。

缺点

所提供的属性是非响应式的。数据追踪比较困难,会将应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。

实例一

父组件向下传递参数father_string,后代组件的表现

父组件

<!-- 父组件 -->
<template>
    <div class="family">
        <div>
            <div>father_string:{{father_string}}</div>
            <p>修改父组件的father_string</p>
            <input v-model="father_string">
        </div>
        <!-- 子组件 -->
        <Son></Son>
        <!-- 子组件 -->
    </div>
</template>

<script>
import Son from "./Son";
export default {
    name: "HelloWorld",
    data () {
        return {
            father_string: "father",
        };
    },
    components: {
        Son,
    },
    provide () {
        return {
            father_string: this.father_string
        }
    }

};
</script>

<style scoped>
.family {
    width: 40%;
    margin: 0 30%;
    display: flex;
    justify-content: space-around;
}
</style>

子组件

 <!-- 子组件 -->
<template>
    <div>
        <div>子组件接受到的father_string</div>
        <div>{{father_string}}</div>
    </div>
    <!-- 孙组件 -->
    <Grandson></Grandson>
    <!-- 孙组件 -->

</template>

<script>
import Grandson from "./Grandson";
export default {
    name: "Son",
    inject: ["father_string"],
    components: {
        Grandson,
    }
};
</script>

孙组件

<!-- 孙组件 -->
<template>
    <div>
        <div>孙子组件father_string:{{father_string}}</div>
        <div>{{father_string}}</div>
    </div>
</template>

<script>
export default {
    name: "Grandson",
    inject: ["father_string"],
};
</script>

实例一效果

初始渲染时,子和子孙组件接受到的参数表现都为father

1.png

改变父组件的参数时,子和子孙组件的非响应式参数表现,如图子孙为非响应

2.png

小结

后代组件可以轻松实现跨级访问父组件的数据,但是当数据改变时,后代组件非响应,没有实时更新

实例二

父组件向下传递参数son_string,子组件也向下传递参数son_string,孙组件的表现

在父组件中新增provide参数son_string

父组件

<!-- 父组件 -->
<template>
    <div class="family">
        <div>
            <div>father_string:{{father_string}}</div>
            <p>修改父组件的father_string</p>
            <input v-model="father_string">
            <div>父亲的son_string:{{son_string}}</div>
        </div>
        <!-- 子组件 -->
        <Son></Son>
        <!-- 子组件 -->
    </div>
</template>

<script>
import Son from "./Son";
export default {
    name: "HelloWorld",
    data () {
        return {
            father_string: "father",
            son_string: "son_string_but from father"
        };
    },
    components: {
        Son,
    },
    provide () {
        return {
            father_string: this.father_string,
            //在这里我们新加了向下传递的son_string
            son_string: this.son_string
            //在这里我们新加了向下传递的son_string
        }
    }
};
</script>
<style scoped>
.family {
    width: 40%;
    margin: 0 30%;
    display: flex;
    justify-content: space-around;
}
</style>

子组件

在子组件中我们也在provide新增参数son_string

<!-- 子组件 -->
<template>
    <div>
        <div>子组件接受到的father_string</div>
        <div>father_string:{{father_string}}</div>
        <div>子组件的son_string:{{son_string}}</div>
    </div>
    <!-- 孙组件 -->
    <Grandson></Grandson>
    <!-- 孙组件 -->

</template>

<script>
import Grandson from "./Grandson";
export default {
    name: "Son",
    inject: ["father_string"],
    provide () {
        return {
            son_string: this.son_string
        }
    },
    data () {
        return {
            son_string: "son_string: "son_string_but from son"
        }
    },
    components: {
        Grandson,
    }
};
</script>

最后在孙组件中接收参数son_string

<!-- 孙组件 -->
<template>
    <div>
        <div>孙子组件father_string:{{father_string}}</div>
        <div>{{son_string}}</div>
    </div>
</template>

<script>
export default {
    name: "Grandson",
    inject: ["father_string", "son_string"],
};
</script>

实例二效果

6.png

总结

从图中我们可以看到孙组件显示的是来自子组件的参数son_string_but from son,而不是来自父组件。由此可见这种传参方式从上而下的注入参数,后代组件并不能知道参数是由谁传递过来的,优先取最近亲的前辈组件传递来的参数,而且他们都是非响应式