Vue组件通信整理

前言

在我们Vue开发中,精髓就是组件,一个优秀的项目中,各种组件总是必不可少,我们暂且将组件分成三类:

  • 路由组件 由vue-router 生成每个页面的组件,承载着每个页面大部分的初始化内容以及业务逻辑;
  • 业务逻辑组件 在一个完整的项目中,经常会出现一些相同的业务逻辑的页面,此时将相同部分的逻辑抽出变成一个组件,在需要的页面倒入即可,这种组件减少了重复工作量,易于维护,但是只适用于当前项目;
  • 基础组件 不包含任何业务逻辑 只包含某种独立功能的基础组件,比如模态框、日历插件等,这种组件适用于大多数项目,通过高度抽象的API 配出处不通的功能。例如element-UI 和 IView库。

所以页面中的组件之间的关系可以如下图:
Vue组件通信整理_第1张图片

A与B 是父子关系 或者隔代关系。 B和C、B和D都是父子关系,C和D是兄弟关系。
因为组件与组件直接的复杂关系,我们每次组件直接的通信传值就变得尤其重要;在适合的项目中,使用适合的传值方式,可以让代码规范性可读性甚至性能上有了很大提高,那么下面我们来系统的讨论一下组件通讯传值的方式

组件与组件传值

我们首先大致罗列出组件直接通信的方式,然后再一一的详细分析:

1. 路由之间传值 将值拼接在路由后面,然后再新页面中 通过 $route.query.xxx方式获取
2. sessionStorage 和 localStorage
3. Vuex
4. 父传子 props
5. $attrs 自定义属性的形式 另外额外使用 v-bind 可以向更深层传递
6. provide/inject 可以 父传子 或者隔代相传
7. $emit + $on 事件传值
8. eventBus 事件传值
9. $ref获取
10. $parent $children

我们一个个的整理:

1、路由参数方式

首先在一个页面点击跳转到对应路由,并将参数拼接在路由后面

  this.$router.push(`/router-test?name=${this.name}&id=${this.id}`)

然后再进入新页面后,通过$route中的query 获取

created () {
    console.log(this.$route.query)
  }

显示内容如下~~
Vue组件通信整理_第2张图片

2、sessionStorage 和 localStorage

简单分析一下两者之间的区别:
localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。
sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过sessionStorage存储的数据也就被清空了。
具体用法也很简单,就不具体用代码演示了,一个页面存数据,一个页面取数据~~

3、$refs

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例;比如在父组件中的子组件实例上,定义一个ref





HelloWord.vue


 ...
 ...


7、 $attr

这个方法的使用我就不再重复的去写了,大家可以看我的另一篇博客 Vue属性 inheritAttrs、$attrs和$listeners初窥

8、EventBus

EventBus 又称之为事件总线。实现的主要原理 我通俗的理解为:
借用Vue中的$emit 和 $on 两个实例方法(独立于整个Vue项目的Vue实例)。
基于这个简单的理解,我们可以将EventBus分为两种:局部 和 全局。

局部EventBus

我们建立一个单独的js 名字就命名为 event-bus.js,内容如下:

import Vue from 'vue'

export const EventBus = new Vue()

非常简单的两行,导出一个新的Vue实例命名为 EventBus,然后我们在哪里用就在那里引入:

// HelloWord.vue





这样我们就实现了组件之间数据通信。

另外,注销事件的方式:

EventBus.$off(‘eventName’, {})    移除xxx事件
EventBus.$off(‘eventName’)     移除xxx事件
EventBus.$off()              移除所有事件

全局EventBus

全局EventBus 比局部的方法更加优雅,但是因为是全局,定义在mian.js中,后期当代码量上来之后可能会导致混乱并不易维护。

// main.js
var EventBus = new Vue();

Object.defineProperties(Vue.prototype, {
    $bus: {
        get: function () {
            return EventBus
        }
    }
})

使用方式也非常简单,不需要再每个使用的组件中单独引用。我们把上面的例子稍稍改动一下就好:

// HelloWord.vue
methods: {
    testEventBus () {
      this.$bus.$emit('addCount', { count: 1 })
    }
  }

// Child.vue
this.$bus.$on('addCount', obj => {
      console.log(obj)
    })
9、provide/inject

provide和inject 这个两个方法总是同时出现,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

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

使用方法如下面示例(HelloWord.vue和child.vue是父子组件):

// HelloWord.vue

export default {
  name: 'HelloWorld',
  provide () {
    return {
      child: 'provide 传入子组件'
    }
  }
  
// child.vue
export default {
  name: 'child',
  inject: ['child'],
  mounted() {
  	console.log(this.child)      // 打印 'provide 传入子组件'
  }
 }

另外provide和inject 还可以作为全局状态管理(一般大型项目还是推荐使用Vuex);我们来看一个demo:

// App.vue
export default {
  name: 'App',
  data () {
    return {
      userinfo: {}
    }
  },
  provide () {
    return {
      app: this
    }
  },
  created () {
    this.getUserinfo('wangyang')
  },
  methods: {
    getUserinfo (name) {
      this.userinfo = {
        name: name,
        age: 28,
        sex: 'man'
      }
    }
  }
}

一般我们的项目中,都会有一个全局使用的用户状态,一般以前我们都是使用 SessionStorage、Vuex去做管理,此时我们使用provide/reject一样可以。我们在最底层的组件App.vue中,设定provide中 app 为 App.vue中的this。当我们去其他组件中如果去调用和修改呢? 请看下面代码:

  // HelloWorld.vue
  
  inject: ['app'],
  mounted () {
    console.log(this.app.userinfo)  //  wangyang
    this.name = this.app.userinfo.name
  },
  methods: {
    editorUser () {
      this.app.getUserinfo('editor')
      this.name = this.app.userinfo.name  // editor
    }
  }

部分代码已省略~~
我们在HelloWorld中mounted生命周期函数值打印this.app.getUserinfo(‘editor’) 值为 wangyang。
然后我们点击页面中的按钮(事件editorUser)将新的name 传入App.vue中的userinfo修改方法getUserinfo。
然后再次打印,name值改变为 editor。

10、Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

在此引用一下官方的定义,我想大家写Vue项目,多少都用到了Vuex,在此我就不过多的介绍它的使用方法了,这也不是一句两句可以解释清楚的。贴出官方文档的连接跳转 Vuex文档。另外网上也有很多优秀的Vuex使用说明博客,有兴趣的童鞋自己去谷歌。

总结

在此列举的Vue组件通信方式并不能包含网上所有的方法。但是学以致用,在适合的项目中使用最好的方法才是我们需要追求的,另外搞懂Vue的整体运作,还需要更多的了解Vue的源码。

参考文章
  • vue篇之事件总线(EventBus)
  • Vue.js 组件精讲

你可能感兴趣的:(Vue)