Vue通过provide inject实现组件通信


Posted in Javascript onSeptember 03, 2020

provide/inject是Vue.js2.2.0版本后新增的API:

provide:Object | () => Object//一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。

inject:Array<string> | { [key: string]: string | Symbol | Object }//一个字符串数组,或一个对象

虽然官方文档说,provide和inject主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中,但是在插件 / 组件库(比如 iView,事实上 iView 的很多组件都在用)。不过建议归建议,如果你用好了,这个 API 会非常有用。

这对选项需要一起使用,以允许一个祖先组件向其所有的子孙后代注入一个依赖,不论组件的层次有多深,并在起上下游关系成立的时间里始终生效。

注意:provide和inject绑定并不是可响应的。这显然不是设计的失误,而是刻意的。

下面我们来看一看它最简单的用法:

//祖先级组件(上级组件)
<template>
  <div>
    <Pro></Pro>
  </div>
</template>
<script>
import Pro from '../components/provide.vue';
export default {
  data(){
    return{
    }
  },
   provide:{
    foo:'test'
  },
  components:{
    Pro,
  }
}
</script>
<style scoped>
</style>
//子孙级组件(下级组件)
<template>
  <div>
    <p>{{foo}}</p>
  </div>
</template>
<script>
export default {
  data(){
    return {
    }
  },
  inject:['foo'],
}
</script>
<style scoped>
</style>

我们在上级组件中设置了一个provide:foo,值为test,它的作用就是将foo这个变量提供给它的所有下级组件。而在下级组件中通过inject注入了从上级组件中提供的foo变量,那么在下级组件中,就可以直接通过this.foo来访问了。

再次强调一遍,provide和inject绑定并不是可响应的,所以上述例子中上级组件的foo改变了,下级组件的this.foo的值还是不会改变的。

我们一般会在main.js中导入app.vue作为根组件,我们需要在app.vue上做文章,这就是我们实现功能的关键。我们可以这样理解:app.vue作为一个最外层的根组件,用来存储所有需要的全局数据和状态。因为项目中的所有组件(包含路由),它的父组件(或根组件)都是app.vue,所有我们可以把整个app.vue实例通过provide对外提供。那么,所有的组件都能共享其数据,方法等。

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  provide () {
   return {
    app: this
   }
  }
 }
</script>

上面,我们把整个app.vue的实例`this`对外提供,接下来,任何组件(或路由)只要通过`inject`注入app.vue的话,都可以通过this.app.xxx的形式来访问app.vue的data,computed,method等内容。

app.vue是整个项目第一个被渲染的组件,而且只会渲染一次(即使切换路由,app.vue也不会被再次渲染),利用这个特性,很适合做一次性全局的状态数据管理,例如我们将用户的登录信息保存起来:

//app.vue,部分代码省略:
<script>
export default {
  provide () {
   return {
    app: this
   }
  },
  data () {
   return {
    userInfo: null
   }
  },
  methods: {
   getUserInfo () {
    // 这里通过 ajax 获取用户信息后,赋值给 this.userInfo,以下为伪代码
    $.ajax('/user/info', (data) => {
     this.userInfo = data;
    });
   }
  },
  mounted () {
   this.getUserInfo();
  }
 }
</script>

这样,任何页面或组件只要通过inject注入app后,就可以直接访问userInfo的数据了,比如:

<template>
 <div>
  {{ app.userInfo }}
 </div>
</template>
<script>
export default {
  inject: ['app']
 }
</script>

是不是很简单呢。除了直接使用数据,还可以调用方法。比如在某个页面里,修改了个人资料,这时一开始在app.vue里获取的userInfo已经不是最新的了,需要重新获取。可以这样使用:

//某个页面:
 
<template>
 <div>
  {{ app.userInfo }}
 </div>
</template>
<script>
export default {
  inject: ['app'],
  methods: {
   changeUserInfo () {
    // 这里修改完用户数据后,通知 app.vue 更新,以下为伪代码
    $.ajax('/user/update', () => {
     // 直接通过 this.app 就可以调用 app.vue 里的方法this.app.getUserInfo();
    })
   }
  }
 }
</script>

同样非常简单。只要理解了 `this.app` 是直接获取整个 `app.vue` 的实例后,使用起来就得心应手了。想一想,配置复杂的 Vuex 的全部功能,现在是不是都可以通过 `provide / inject` 来实现了呢?

如果你顾忌 Vue.js 文档中所说,provide / inject 不推荐直接在应用程序中使用,那没有关系,仍然使用你熟悉的 Vuex 或 Bus 来管理你的项目就好。我们介绍的这对 API,主要还是在独立组件中发挥作用的。

只要一个组件使用了 `provide` 向下提供数据,那其下所有的子组件都可以通过 `inject` 来注入,不管中间隔了多少代,而且可以注入多个来自不同父级提供的数据。需要注意的是,一旦注入了某个数据,比如上面示例中的 `app`,那这个组件中就不能再声明 `app` 这个数据了,因为它已经被父级占有。

进阶技巧:

如果你的项目足够复杂,或需要多人协同开发时,在app.vue里会写非常多的代码,多到结构复杂难以维护。这时可以使用 Vue.js 的混合mixins,将不同的逻辑分开到不同的 js 文件里。

我先简单介绍一下什么是mixins:

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。(个人理解mixins就是定义一部分公共的方法或者计算属性,然后混入到各个组件中使用,方便管理与统一修改)

比如上面的用户信息,就可以放到混合里:

//新建文件(user.js)
export default {
 data () {
  return {
   userInfo: null
  }
 },
 methods: {
  getUserInfo () {
   // 这里通过 ajax 获取用户信息后,赋值给 this.userInfo,以下为伪代码
   $.ajax('/user/info', (data) => {
    this.userInfo = data;
   });
  }
 },
 mounted () {
  this.getUserInfo();
 }
}

然后在app.vue中混合:

<script>
 import mixins_user from'../mixins/user.js';
 export default {
  mixins: [mixins_user],
  data () {
   return {
   }
  }
 }
</script>

这样,跟用户信息相关的逻辑,都可以在user.js里维护,或者由某个人来维护,app.vue也就很容易维护了。

要深入了解混入请参照官方文档:https://cn.vuejs.org/v2/guide/mixins.html

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js 分栏效果实现代码
Aug 29 Javascript
JavaScript日历实现代码
Sep 12 Javascript
jquery获取子节点和父节点的示例代码
Sep 10 Javascript
jQuery实现单击弹出Div层窗口效果(可关闭可拖动)
Sep 19 Javascript
JS+CSS实现闪烁字体效果代码
Apr 05 Javascript
JS实现图片延迟加载并淡入淡出效果的简单方法
Aug 25 Javascript
JavaScript获取服务器端时间的方法
Nov 29 Javascript
vue.js整合mint-ui里的轮播图实例代码
Dec 27 Javascript
vue.js使用3DES加密的方法示例
May 18 Javascript
angular6 利用 ngContentOutlet 实现组件位置交换(重排)
Nov 02 Javascript
微信小程序webview实现长按点击识别二维码功能示例
Jan 24 Javascript
vue父子组件通信的高级用法示例
Aug 29 Javascript
Vue组件通信$attrs、$listeners实现原理解析
Sep 03 #Javascript
Vue父组件监听子组件生命周期
Sep 03 #Javascript
JavaScript 几种循环方式以及模块化的总结
Sep 03 #Javascript
Vuejs通过拖动改变元素宽度实现自适应
Sep 02 #Javascript
Vue Object.defineProperty及ProxyVue实现双向数据绑定
Sep 02 #Javascript
Vue 组件的挂载与父子组件的传值实例
Sep 02 #Javascript
vue中的.$mount('#app')手动挂载操作
Sep 02 #Javascript
You might like
PHP封装的Twitter访问类实例
2015/07/18 PHP
深入理解PHP JSON数组与对象
2016/07/19 PHP
passwordStrength 基于jquery的密码强度检测代码使用介绍
2011/10/08 Javascript
javascript获取ckeditor编辑器的值(实现代码)
2013/11/18 Javascript
js面向对象编程之如何实现方法重载
2014/07/02 Javascript
js实现二代身份证号码验证详解
2014/11/20 Javascript
浅谈javascript中onbeforeunload与onunload事件
2015/12/10 Javascript
Bootstrap每天必学之标签页(Tab)插件
2020/08/09 Javascript
jQuery中checkbox反复调用attr('checked', true/false)只有第一次生效的解决方法
2016/11/16 Javascript
jQuery加载及解析XML文件的方法实例分析
2017/01/22 Javascript
JavaScript之面向对象_动力节点Java学院整理
2017/06/29 Javascript
在Js页面通过POST传递参数跳转到新页面详解
2017/08/25 Javascript
React-Native左右联动List的示例代码
2017/09/21 Javascript
vue 标签属性数据绑定和拼接的实现方法
2018/05/17 Javascript
JavaScript实现更换背景图片
2019/10/18 Javascript
关于vue利用postcss-pxtorem进行移动端适配的问题
2019/11/20 Javascript
JS实现点击下拉列表文本框中出现对应的网址,点击跳转按钮实现跳转
2019/11/25 Javascript
VueX模块的具体使用(小白教程)
2020/06/05 Javascript
原生js 实现表单验证功能
2021/02/08 Javascript
vue项目配置 webpack-obfuscator 进行代码加密混淆的实现
2021/02/26 Vue.js
[35:44]2014 DOTA2华西杯精英邀请赛 5 24 iG VS VG
2014/05/26 DOTA
用生成器来改写直接返回列表的函数方法
2017/05/25 Python
python机器学习实战之树回归详解
2017/12/20 Python
Python for循环与range函数的使用详解
2019/03/23 Python
Python简易版图书管理系统
2019/08/12 Python
python 类的继承 实例方法.静态方法.类方法的代码解析
2019/08/23 Python
Python常用模块函数代码汇总解析
2020/08/31 Python
Python 排序最长英文单词链(列表中前一个单词末字母是下一个单词的首字母)
2020/12/14 Python
CSS3实现同时执行倾斜和旋转的动画效果
2016/10/27 HTML / CSS
香港时尚女装购物网站:ZAFUL
2017/07/19 全球购物
.NET程序员的数据库面试题
2012/10/10 面试题
爱心倡议书范文
2014/05/12 职场文书
小学捐书活动总结
2014/07/05 职场文书
先进个人材料怎么写
2014/12/30 职场文书
委托函范文
2015/01/29 职场文书
入党后的感想
2015/08/10 职场文书