百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

组件通信:在独立组件中使用provide与inject模拟跨组件vuex,Bus

ztj100 2024-11-12 14:21 74 浏览 0 评论

上一篇中我们说到,ref 和 $parent / $children跨级通信时是有弊端的。当组件 A 和组件 B 中间隔了数代(甚至不确定具体级别)时,以往会借助 Vuex 或 Bus 这样的解决方案,不得不引入三方库来支持。本文介绍一种无依赖的组件通信方法:Vue.js 内置的 provide / inject 接口。

什么是 provide / inject

provide / inject 是 Vue.js 2.2.0 版本后新增的 API,文档中有如下提示:

provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

就是说 Vue.js 不建议在业务中使用这对 API,而是在插件 / 组件库(比如 iView,事实上 iView 的很多组件都在用)。

我们先来看一下这个 API 怎么用,假设有两个组件: A.vueB.vue,B 是 A 的子组件。

// A.vue
export default {
 provide: {
 name: 'Aresn'
 }
}
// B.vue
export default {
 inject: ['name'],
 mounted () {
 console.log(this.name); // Aresn
 }
}

可以看到,在 A.vue 里,我们设置了一个 provide: name,值为 hello,它的作用就是将 name 这个变量提供给它的所有子组件。而在 B.vue 中,通过 inject 注入了从 A 组件中提供的 name 变量,那么在组件 B 中,就可以直接通过 this.name 访问这个变量了,它的值也是 hello。这就是 provide / inject API 最核心的用法。

需要注意的是:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

所以,上面 A.vue 的 name 如果改变了,B.vue 的 this.name 是不会改变的,仍然是 hello。

替代 Vuex

我们知道,在做 Vue 大型项目时,可以使用 Vuex 做状态管理,它是一个专为 Vue.js 开发的状态管理模式,用于集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

那了解了 provide / inject 的用法,下面来看怎样替代 Vuex。当然,我们的目的并不是为了替代 Vuex,它还是有相当大的用处,这里只是介绍另一种可行性。

使用 Vuex,最主要的目的是跨组件通信、全局数据维护、多人协同开发。需求比如有:用户的登录信息维护、通知信息维护等全局的状态和数据。

一般在 webpack 中使用 Vue.js,都会有一个入口文件 main.js,里面通常导入了 Vue、VueRouter、iView 等库,通常也会导入一个入口组件 app.vue 作为根组件。一个简单的 app.vue 可能只有以下代码:

使用 provide / inject 替代 Vuex,就是在这个 app.vue 文件上做文章。

我们把 app.vue 理解为一个最外层的根组件,用来存储所有需要的全局数据和状态,甚至是计算属性(computed)、方法(methods)等。因为你的项目中所有的组件(包含路由),它的父组件(或根组件)都是 app.vue,所以我们把整个 app.vue 实例通过 provide 对外提供

app.vue:

上面,我们把整个 app.vue 的实例 this 对外提供,命名为 app(这个名字可以自定义,推荐使用 app,使用这个名字后,子组件不能再使用它作为局部属性)。接下来,任何组件(或路由)只要通过 inject 注入 app.vue 的 app 的话,都可以直接通过 this.app.xxx 来访问 app.vue 的 data、computed、methods 等内容。

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 来实现了呢?

进阶技巧

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

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

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 中混合:

app.vue:

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

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

独立组件中使用

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

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

独立组件使用 provide / inject 的场景,主要是具有联动关系的组件。

相关推荐

sharding-jdbc实现`分库分表`与`读写分离`

一、前言本文将基于以下环境整合...

三分钟了解mysql中主键、外键、非空、唯一、默认约束是什么

在数据库中,数据表是数据库中最重要、最基本的操作对象,是数据存储的基本单位。数据表被定义为列的集合,数据在表中是按照行和列的格式来存储的。每一行代表一条唯一的记录,每一列代表记录中的一个域。...

MySQL8行级锁_mysql如何加行级锁

MySQL8行级锁版本:8.0.34基本概念...

mysql使用小技巧_mysql使用入门

1、MySQL中有许多很实用的函数,好好利用它们可以省去很多时间:group_concat()将取到的值用逗号连接,可以这么用:selectgroup_concat(distinctid)fr...

MySQL/MariaDB中如何支持全部的Unicode?

永远不要在MySQL中使用utf8,并且始终使用utf8mb4。utf8mb4介绍MySQL/MariaDB中,utf8字符集并不是对Unicode的真正实现,即不是真正的UTF-8编码,因...

聊聊 MySQL Server 可执行注释,你懂了吗?

前言MySQLServer当前支持如下3种注释风格:...

MySQL系列-源码编译安装(v5.7.34)

一、系统环境要求...

MySQL的锁就锁住我啦!与腾讯大佬的技术交谈,是我小看它了

对酒当歌,人生几何!朝朝暮暮,唯有己脱。苦苦寻觅找工作之间,殊不知今日之事乃我心之痛,难道是我不配拥有工作嘛。自面试后他所谓的等待都过去一段时日,可惜在下京东上的小金库都要见低啦。每每想到不由心中一...

MySQL字符问题_mysql中字符串的位置

中文写入乱码问题:我输入的中文编码是urf8的,建的库是urf8的,但是插入mysql总是乱码,一堆"???????????????????????"我用的是ibatis,终于找到原因了,我是这么解决...

深圳尚学堂:mysql基本sql语句大全(三)

数据开发-经典1.按姓氏笔画排序:Select*FromTableNameOrderByCustomerNameCollateChinese_PRC_Stroke_ci_as//从少...

MySQL进行行级锁的?一会next-key锁,一会间隙锁,一会记录锁?

大家好,是不是很多人都对MySQL加行级锁的规则搞的迷迷糊糊,一会是next-key锁,一会是间隙锁,一会又是记录锁。坦白说,确实还挺复杂的,但是好在我找点了点规律,也知道如何如何用命令分析加...

一文讲清怎么利用Python Django实现Excel数据表的导入导出功能

摘要:Python作为一门简单易学且功能强大的编程语言,广受程序员、数据分析师和AI工程师的青睐。本文系统讲解了如何使用Python的Django框架结合openpyxl库实现Excel...

用DataX实现两个MySQL实例间的数据同步

DataXDataX使用Java实现。如果可以实现数据库实例之间准实时的...

MySQL数据库知识_mysql数据库基础知识

MySQL是一种关系型数据库管理系统;那废话不多说,直接上自己以前学习整理文档:查看数据库命令:(1).查看存储过程状态:showprocedurestatus;(2).显示系统变量:show...

如何为MySQL中的JSON字段设置索引

背景MySQL在2015年中发布的5.7.8版本中首次引入了JSON数据类型。自此,它成了一种逃离严格列定义的方式,可以存储各种形状和大小的JSON文档,例如审计日志、配置信息、第三方数据包、用户自定...

取消回复欢迎 发表评论: