Vuex以及几种组件通讯的使用

先来看看一个简单德例子

target.png

一个带按钮和计数器的简单应用程序。按下按钮会使计数器递增。虽然这很容易实现,但目标是理解基本概念。

problem.dot.png

假设应用程序中有两个组件:

1、一个按钮(事件的来源)
2、计数器(必须根据原始事件反映更新)
这两个组件彼此不了解,无法相互通信。即使是最小的Web应用程序,这也是一种非常常见的模式。在较大的应用程序中,许多组件相互通信,并且必须相互控制。以下是基本待办事项列表的一些交互:


todo.dot.png

这篇文章的目标

我们将探索解决同一问题的四种方法:
1、使用事件广播在组件之间进行通信
2、使用共享状态对象
3、使用vuex

首先,我们IncrementButton在src/components/IncrementButton.vue以下位置创建组件:

<template>
  <button @click.prevent="activate">+1</button>
</template>
<script>
export default {
  methods: {
    activate () {
      console.log('+1 Pressed')
    }
  }
}
</script>

<style>
</style>

接下来,我们创建CounterDisplay实际显示计数器的组件。让我们创建一个新的基本vue组件src/components/CounterDisplay.vue

<template>
  Count is {{ count }}
</template>

<script>
export default {
  data () {
    return {
      count: 0
    }
  }
}
</script>
<style>
</style>

替换App.vue为此文件:

<template>
  <div id="app">
    <h3>Increment:</h3>
    <increment></increment>
    <h3>Counter:</h3>
    <counter></counter>
  </div>
</template>

<script>
import Counter from './components/CounterDisplay.vue'
import Increment from './components/IncrementButton.vue'
export default {
  components: {
    Counter,
    Increment
  }
}
</script>

<style>
</style>

现在,如果npm run dev再次运行,并在浏览器中打开页面,您应该会看到一个按钮和一个计数器。单击该按钮会在控制台中显示一条消息

解决方案1:事件广播

solution1.dot.png

让我们修改组件中的脚本。首先,IncrementButton.vue我们使用$dispatch向父级发送一条消息,单击该按钮

export default {
  methods: {
    activate () {
      // Send an event upwards to be picked up by App
      this.$dispatch('button-pressed')
    }
  }
}

在App.vue我们收听来自孩子的事件并重新向所有孩子广播新事件以增加。

export default {
  components: {
    Counter,
    Increment
  },
  events: {
    'button-pressed': function () {
      // Send a message to all children
      this.$broadcast('increment')
    }
  }
}
>在CounterDisplay.vue我们听取increemnt事件并增加状态的价值。

export default {
  data () {
    return {
      count: 0
    }
  },
  events: {
    increment () {
      this.count ++
    }
  }
}

这种方法的一些缺点:

1、对于每个操作,父组件需要连接并将事件“分派”到正确的组件。
2、对于更大的应用程序来说,很难理解事件的来源。
3、业务逻辑可以在任何地方,这可能使其无法维护。

解决方案2:共享状态

让我们回复一下我们在解决方案1中所做的一切。我们创建一个新文件 src/store.js

export default {
  state: {
    counter: 0
  }
}

我们先修改一下CounterDisplay.vue:

<template>
  Count is {{ sharedState.counter }}
</template>

<script>
import store from '../store'

export default {
  data () {
    return {
      sharedState: store.state
    }
  }
}
export default store
</script>

我们可以修改IncrementButton.vue

import store from '../store'

export default {
  data () {
    return {
      sharedState: store.state
    }
  },
  methods: {
    activate () {
      this.sharedState.counter += 1
    }
  }
}

解决方案3:Vuex

定义一个vuex.js文件,并在main.js里面引入

1.在main.js里面引入vuex

import Vuex from 'vuex'
import vuexs from './vuex'
Vue.use(Vuex);
const appVuex = new Vuex.Store({
    vuexs 
})
new Vue({
  el: '#app',
  router,
  appVuex ,
  components: { App },
  template: '<App/>'
})

vuex.js文件代码如下

const state = {
 count :0
}
const mutations={
  changeMenuIndex(state, num) {
     state.count = num
  }
 }
 const actions={
    post:function(context,payload){//这里的context和我们使用的$store拥有相同的对象和方法
       return new Promise(function(resolve, reject){
         axios.post(payload.path,payload.datas).then(data=>{
            resolve(data)
         })
       });
    }
}
export default {
    state,
    mutations,
    actions
}

state里面定义自己需要的变量,这里面的变量只能通过mutations,或者actions改变,以下是获取state变量方式

1、在计算属性中返回某个状态:

<div>{{ count }}</div>
computed: {
    count () {
      return store.state.count
    }
  }

2、mapState 辅助函数

import {mapState} from "vuex";
computed: {
          ...mapState(['count'])
        },

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

const mutations={
  changeMenuIndex(state, num) {
     state.count = num
  }
 }
// 在组件中使用,num为传过来的参数
this.$store.commit('changeMenuIndex', 10);

//这里有个问题就是怎样传多个参数,mutations只能定义两个参数,所以这里只能以对象的形式传值
const mutations={
  changeMenuIndex(state, payload) {
     state.count = payload.vuexNum
  }
 }
this.$store.commit('changeMenuIndex', {
   vuexNum: 10
});
//也可以这样传,type为函数名,其他的都是传参
store.commit({
  type: 'changeMenuIndex',
  vuexNum: 10
})

这里可以使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    // mapMutations 工具函数会将 store 中的 commit 方法映射到组件的 methods 中
    ...mapMutations([
      'changeMenuIndex', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}

Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。

const actions={
  //写法一
  increment (context) {
      context.commit('increment')
  }
  //写法二
  increment ({ commit }) {
     commit('changeMenuIndex')
  }
 }
// 这里用到了对象的结构
//因为函数的参数是一个对象,函数中用的是对象中一个方法,我们可以通过对象的
//解构赋值直接获取到该方法
//因为context本身就是一个对象,里面有state对象和commit方法例如
let context {
   state: {},
   commit: function(){}
}
//根据对象结构可以定义如下:
let {state,commit} = context
console.log(state)//state: {};
console.log(commit)//commit: function(){};
//所以放在函数里面就是
increment ({state,commit} ) {
     commit('changeMenuIndex')
  }
//具体es6的用法可以参考
`http://es6.ruanyifeng.com/`

在组件中使用this.$store.dispatch('increment ',10);,这里的传参与上面讲的一样,这些都是一些常用的东西,还有一些如getter和moudle等可以看看文档
https://vuex.vuejs.org/zh/guide/actions.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • Vuex是什么? Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件...
    萧玄辞阅读 3,102评论 0 6
  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应...
    白水螺丝阅读 4,652评论 7 61
  • 安装 npm npm install vuex --save 在一个模块化的打包系统中,您必须显式地通过Vue.u...
    萧玄辞阅读 2,924评论 0 7
  • 目录 - 1.什么是vuex? - 2.为什么要使用Vuex? - 3.vuex的核心概念?||如何在组件中去使用...
    我跟你蒋阅读 4,109评论 4 51
  • 作者:胡杨映月 在现实生活中,我们都以为婚外情所不齿,当然,我们确实也不赞同婚外情,这种行为确实与我们几千年的情感...
    胡杨映月阅读 1,160评论 0 2