组件之间的多层传值我们前面学习过了通过$attrs和$listeners,今天我们来学习一个更为简单的方法利用组件对象的属性provide和inject,它们与data、methods这些属于同级。
用法:在需要提供数据的组件内设置provide,其设置的属性值为对象或者为函数的返回值对象;在需要获取数据的组件内直接用inject注入到当前组件中,不管你处于那一层都能够获取到,inject属性的值为一个字符串数组,或一个对象,对象的情况可具体查看官方API。
用三个组件演示一下:爷爷组件、父亲组件、孙子组件
爷爷组件:提供数据
- <div class="app">
- <div>{{msg}}div>
- <Box1>Box1>
- div>
-
- <script>
- import Box1 from "@/components/box1.vue"
- export default {
- data() {
- return {
- msg:"爷爷组件的数据"
- }
- },
- provide:function(){
- return {
- msg:this.msg
- }
- },
- components:{
- Box1
- },
- }
- script>
-
- <style>
- .app{
- width: 300px;
- height: 300px;
- background-color: aquamarine;
- }
- style>
父亲组件:可以被注入提供的数据
- <div class="box1">
- <h2>box1组件h2>
- <div>{{msg}}div>
- <Box2>Box2>
- div>
- <script>
- import Box2 from "./box2.vue"
- export default{
- components:{
- Box2
- },
- inject:["msg"]
- }
- script>
- <style>
- .box1{
- width: 150px;
- height: 150px;
- background-color: aqua;
- }
- style>
孙子组件:也可以获取数据
- <div class="box2">
- <h3>box3组件h3>
- <div> {{msg}}div>
- div>
- <script>
- export default{
- inject:["msg"]
- }
- script>
- <style>
- .box2{
- width: 100px;
- height:100px;
- background-color: yellow;
- }
- style>
页面效果:
但是它有一个缺点就是数据不是响应式的,如我在爷爷组件方法内修改提供的值,但是子组件中获取的值不会改变。
演示一下,修改爷爷组件的代码:
- <div class="app">
- <div>{{msg}}div>
- <button v-on:click="change">修改msgbutton>
- <Box1>Box1>
- div>
-
- <script>
- import Box1 from "@/components/box1.vue"
- export default {
- data() {
- return {
- msg:"爷爷组件的数据"
- }
- },
- methods: {
- change(){
- this.msg="修改了"
- }
- },
- // provide:{msg:this.msg}
- provide:function(){
- return {
- msg:this.msg
- }
- },
- components:{
- Box1
- },
- }
- script>
-
- <style>
- .app{
- width: 300px;
- height: 300px;
- background-color: aquamarine;
- }
- style>
当我们点击按钮修改了msg后,只有父组件内页面数据发生了变化,效果:
解决办法:提供的数据变成一个对象如provide:{msg:{...}},因为对象是一种引用数据,它在内存开辟了一块内存空间。被注入的的组件引用也是指向这块地址,所以能够改变。
再修改代码:
- <div class="app">
- <div>{{msg}}div>
- <button v-on:click="change">修改msgbutton>
- <Box1>Box1>
- div>
-
- <script>
- import Box1 from "@/components/box1.vue"
- export default {
- data() {
- return {
- msg:{msg:"对象形式传入"}
- }
- },
- methods: {
- change(){
- this.msg="修改了"
- }
- },
- // provide:{msg:this.msg}
- provide:function(){
- return {
- msg:this.msg
- }
- },
- components:{
- Box1
- },
- }
- script>
-
- <style>
- .app{
- width: 300px;
- height: 300px;
- background-color: aquamarine;
- }
- style>
修改子组件中{{msg}}-->{{msg.msg}}
再次点击按钮查看效果: