文章参考

  1. vue中provide和inject使用
  2. Vue官网-依赖注入
  3. Vue 依赖注入 - Provide/Inject
  4. provide-inject API 官网例子

问题描述

  1. 在工作中,发现 一个组件中添加一个添加搜索按钮的属性,就会影响到另外一个搜索的组件,这两个组件同时被一个“布局”组件包裹,不管我怎么控制相关的属性,都没有办法让搜索内容显示出来,最后查看了源码,了解到了使用的技术点 —— inject 和 provider

官方案例

看了很多网上的博客,场景应用大部分都形容的不怎么贴切,我个人更喜欢官网的例子

<google-map>
  <google-map-region v-bind:shape="cityBoundaries">
    <google-map-markers v-bind:places="iceCreamShops"></google-map-markers>
  </google-map-region>
</google-map>

问题描述说明?

  1. <google-map-region> 和 <google-map-markers> 这两个组件都需要依赖 gooogleMap 实例对象
  2. 而gooogleMap 实例对象是在 <google-map>组件中的
  3. <google-map> 与 (<google-map-region> )这两个组件是嵌套关系,但是并不是父子关系
  4. 问题是如何把这个实例对象传递给嵌套在里面两个组件中去呢?

解决思路

  1. 把gooogleMap 实例对象 放到他们共用的父组件中,然后通过父组件传递给子组件
  2. 使用Vuex存储 googleMap对象
  3. 使用provide 和 inject; 也是我们今天要学习的内容

如何理解 provide 和 inject

  1. provide 选项允许我们指定我们想要提供给后代组件的数据/方法
  2. 使用 inject 选项来接收指定的我们想要添加在这个实例上的 property

个人理解:

就是说在组件中定以了一个provide属性,提供当前组件中的某些数据或者方法,组件的 children 节点组件使用inject方式就能获取到提供provide的数据或者方法,类似于React中的Provider 和 Consumer

使用场景

组件是嵌套关系,但是并不是父子关系

API 使用说明

provide:Object | () => Object

值是对象
export default {
  ...
  // 父级组件提供 'foo'
  provide: {
    foo: 'bar'
  }
}

要访问组件实例(this) property,我们需要将 provide 转换为返回对象的函数

值是一个function返回对象(推荐,Vue3不支持)
export default {
  ...
  provide: function () {
    return {
      screenContext: this
    }
  }
}

inject:Array | { [key: string]: string | Symbol | Object }

数组接收父组件的provider
// 子组件注入 'foo'
export default {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}
JSON对象接收
export default {
  inject: { 
	foo: "foo"
  },
  // ...
}
设置默认值使其变成可选项

如果它需要从一个不同名字的 property 注入,则使用 from 来表示其源 property

export default {
  inject: {
    foo: {
      from: 'bar',
      default: 'foo'
    }
  }
}

例子

Vue-cli脚手架中使用

  1. provider 提供数据给子组件
export default {
  name: 'Screen',
  provide: function () {
    return {
      screenContext: this // 把当前Vue对象提供给所有子组件可以访问
    }
  },
}  
  1. 子组件使用inject 接受父组件传递的值
export default {
  inject: {
    screenContext: {
      from: 'screenContext'
    }
  },
  methods: {
    createLineChart () {
      this.screenContext.selectCreateTime = 'fghjkl' // 直接改变父组件的值
    }
  }
}

HTML页面中使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>provide + inject</title>
  <script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
</head>
<body>
  <div id="app"></div>
</body>
</html>

<script>
  Vue.component('A', {
    template: `
      <div>
        <B></B>
      </div>
    `,
    provide: {
      msg: '1234124'
    }
  })
  Vue.component('B', {
    template: `
      <div>
        <label>B:</label>
        <span>{{ this.msg }}</span>
        <C></C>
      </div>
    `,
    provide: {
      msg: '42341234',
      name: 'asdasda'
    },
    inject: ['msg'],
  })

  Vue.component('C', {
    template: `
      <div>
        <label>C:</label>
        <span>{{ this.xingming }}</span>
        <span>{{ this.msg }}</span>
      </div>
    `,
    inject: {
      xingming: { // 给变量重命名
        from: 'name',
        default: ''
      },
      msg: {
        from: 'msg',
        default: ''
      }
    },
    data() {
      return {
      }
    },
  })
  var app=new Vue({
    el: '#app',
    template: `
      <div>
        <A />
      </div>
    `
  });
</script>
  1. inject定以的数据使用 this.名 方式调用,例如 this.msg
  2. this.xingming 重新定义了变量,但是值是从父组件定义的 msg 名字的值

运行结果:
在这里插入图片描述

Logo

前往低代码交流专区

更多推荐