vue2.0开发聊天程序(三)组件的通信

天地不仁以万物为刍狗,宇宙无义视众生如蝼蚁
                  ——萧鼎和我

上一节列出了5个关键点,第一个路由已经解决了,接下来解决第二个问题:

组件的通信问题

一、组件的关系

组件之间的关系无非就是两种父子关系没有父子关系。为什么我这样说呢?
按道理应该还有兄弟关系(也就是并列的组件,比如一个组件中引用了hreder和footer组件。),还有爷孙关系(比如我有七个Calabash Brothers组件,放在的HanHan组件下,而HanHan组件放在了Chairman Mao组件下)
那么不应该是父子、爷孙、兄弟关系吗?
然而并不是,因为我看了vue的文档。他的意思就是父子通信和非父子通信。

二、父子之间的通信——Prop和自定义事件

组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。
prop 是父组件用来传递数据的一个自定义属性。子组件需要显式地用 props 选项声明 “prop”。
将我们的App.vue当作父组件,将test当作子组件(什么当作,本来就是)。
在App.vue中修改我们的

    
    

在Test.vue中接收,并在页面中显示:







然后在浏览器的显示效果如下:
vue2.0开发聊天程序(三)组件的通信_第1张图片

综上所述可以看出,其实所谓的prop就是在标签添加一个自定义的属性,然后在子组件中取出这个属性,用Jquery也可以做嘛(满脑子,骚,骚想法.jpg)。

上面的例子很漂亮的把父传子的通信方式展现出来了。但是子传父呢?
vue文档中使用的自定义事件。

使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件

我们还是用APP.vue作为父组件,Test.vue作为子组件
App.vue

...
/*增加一个位置来显示子组件传过来的值*/

我儿子对我说: {{noSay}}

/* 增加一个自定义的事件mychild,并给他指定触发的方法*/ ... data () { return { noSay: '' // 用来接收子组件穿过来的数据 } }, methods: { toFatherSay: function(massage) { // mychlid事件触发调用的方法 this.noSay = massage // massage就是子组件穿过来的内容 } }

Test.vue

....
/*增加一个按钮,一点击就向父组件传值*/

....
data() {
      return {
          massage: '我才不说呢' // 定义一个向父组件传递的值
      }
  },
  methods: {
      toFather: function() { // 按钮点击触发的方法
          this.$emit('myChild',this.massage)// 使用$emit来向父组件传播
      }
  },
....

做完以上操作之后在浏览器上测试:
vue2.0开发聊天程序(三)组件的通信_第2张图片

三、非父子关系之间的通信——eventBus

在veu文档上,非父子之间的通信是通过使用一个空的Vue实例作为中央事件总线。
空的Vue实例? and 中央事件总线?
空的Vue实例也就是说

    var bus = new Vue(); // 的确是一个空的

中央事件总线,难道组件通信要通过全局的事件来进行?
的确是这样,vue提供了$emit和$on方法来进行参数监听(其实就是个发布订阅模式)。
创建一个空的Vue实例 Bus.js:

import Vue from 'vue'
export default new Vue();

将我们的Apart.vue和Bpart.vue当作非父子关系组件:
Apart.vue







Bpart.vue







然后在浏览器中测试一下:

有问题!!!无论怎么点击我们发现Bpart中定义的whiteSay并没有改变,并且第一次点击控制台没有打印。我在Bpart中写了这段代码:

   data () {
      return {
          whiteSay: 'nihao'
      }
  },
  created: function() { // 在组件被创建时候将会执行此函数  相当于进入页面的自执行
      Bus.$on('whiteSay', function(data) { // 使用$on方法监听white属性并执行一个回调函数
          this.whiteSay = data
          console.log(this.whiteSay)
      });
  }

按道理在元素被创建的时候,会将监听到的值赋给whiteSay并且打印。但是我们注意到第一次点击,两个操作都没有执行,也就是说没有监听到whiteSay值的变化。而第二次之后都监听到了。这是为什么?为什么把值赋给data中定义的whiteSay之后没有网页没有更新?
带着这两个问题我去问了度娘和股哥。一下是答案:
第一个为什么: 项目中使用了vue-router,会先加載新的組件,等新的組件渲染好但是還沒掛載前,銷毀舊組件,在掛載新組件。将Apart.vue的代码修改为:

    ...
 methods: {
      goPage: function () {
          this.$router.push('/bb')
      }
  },
  /*Vue 实例销毁后调用 就是所谓的生命周期钩子*/
  destroyed() {
    Bus.$emit('whiteSay', '克里斯,关下门') // 使用$emit方法创建一个键值对
    },
    ...

这样第一个问题就解决了。附上找到的答案连接:https://segmentfault.com/q/10...
第二个为什么:这个是我自己代码有问题,问了隔壁大神。说是我的作用域有问题,将Bpart.vue中的代码改为:

···
 created: function() { // 在组件被创建时候将会执行此函数  相当于进入页面的自执行
     var _self = this; // 将当前作用域保存在变量中,和$on()的作用域区分开来
      Bus.$on('whiteSay', function(data) { // 使用$on方法监听white属性并执行一个回调函数
          _self.whiteSay = data
          console.log(_self.whiteSay)
      });
  }
···

这样所有的问题就都解决了。

四、Vuex
当我使用了上面几种方法来实现组件的通信存在着一些缺陷。比如父组件向子组件传一个值,子组件将值处理完了返回给父组件,这将同时用到prop和自定义事件。还不如直接写一个所有组件都可以访问的变量呢来得方便呢。比如:

/*这是vuex文档中的例子*/
const sourceOfTruth = {}
const vmA = new Vue({
  data: sourceOfTruth
})
const vmB = new Vue({
  data: sourceOfTruth
})

再比如当项目过大,组件之间的通信将变得难以管理。veux的初衷就是为何更好的管理组件的状态。一下是vuex文档对vuex的定义:

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

写得好累,还好最近没事做,不会被boss骂。

接下来直接开始使用vuex。

先下载
在根目录下打开cmd:

npm install vuex -save

下载成功看到一下数据:

C:\Users\59227\Desktop\x-chat>npm install vuex --save
[email protected] C:\Users\59227\Desktop\x-chat
`-- [email protected]

npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: [email protected]

然后在main.js中引用,并安装到Vue上面

import Vuex from 'vuex'

Vue.use(Vuex)

前面两步将Vuex引入到了项目当中,接下来如何使用Vuex。
Vuex的核心是一个store(仓库)这个仓库的作用就是用来管理应用中的state(状态)。这里状态该怎么理解?
我个人的理解是:所有组件共享的并可以进行更改的对象。
除了state的,store还有getter、Mutations、Actions以及Modules。在vuex文档中都有非常详细的说明:http://vuex.vuejs.org/zh-cn/s...
笼统的说:

组件获取 state 用 vuex 的 getter
组件触发动作用 vuex 的 action
修改 state 用 vuex 的 mutation

知乎上看到的,说得很贴切易懂。

直接上代码,建议撸完代码,再去看一遍vuex的文档。

main.js

....
const store = new Vuex.Store({ //创建一个仓库
    state: {  
        showDagger: true, // 定义一个状态
    },
    mutations: {// 定义 mutation ,更改 Vuex 的 store 中的状态的唯一方法是提交mutation
        daggerCtrl (state) { // 一定要传入state,并且是第一个参数
            state.showDagger = !state.showDagger  // 将showDagger值取反
        }
    }
})
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router, // 将router对象传给vue,这样就可以通过this.$router获取到router对象了
  store, // 将store对象传给vue,这样就可以通过this.$store获取到store对象了
  template: '', 
  components: { App }
})

然后更改App.vue:






dagger.vue





打开浏览器 看效果:
vue2.0开发聊天程序(三)组件的通信_第3张图片

使用vuex实现组件通信就搞定了,更多的用法请参考vuex文档。

你可能感兴趣的:(vue2.0开发聊天程序(三)组件的通信)