【Vue】组件间通信

单向传值(props):父组件向子组件传值,任何类型的值都可以传给一个 prop。

实现概述:父组件通过指令向子组件传值,子组件通过props接收。

// 父组件-App.vue

<template>
  <div id="app">
    <!-- <com age="19"></com> // 静态传递 prop -->
    <com :age="age"></com> <!-- // 动态传递 prop -->
  </div>
</template>

<script>
import com from './components/com'  // 引入子组件

export default {
  name: 'app',
  components: {
    com // 注册子组件
  },
  data () {
    return {
      age: 108 // 父组件定义变量
    }
  }
}
</script>
// 子组件 com.vue

<template>
  <div>child components {{name}} {{age}}</div>
</template>
<script>
export default {
  props: ['age'], // 子组件用props接收父组件传递的值
  data () {
    return {
      name: 'com'
    }
  }
}
</script>

单向传值:子组件向父组件传值,自定义事件。结合父组件传值达到了父子组件通信的功能。

实现概述:

1、父组件通过指令将数组传递给子组件,子组件通过props接收,此时数据流向是从父组件到子组件

2、子组件通过自定义事件将行为传给父组件,父组件触发自定义事件并改变数据源,此时形成一个闭环的数据流

// 子组件 com.vue

<template>
  <div>
    child components{{age}}
    <!-- 子组件通过$emit()自定义事件并可以传参 -->
    <button @click="$emit('patch', 66)">给父组件传值</button>
  </div>
</template>
<script>
export default {
  props: ['age']
}
</script>
<template>
  <div id="app">  
    <!-- 父组件触发子组件的自定义事件 -->  
    <com :age="ages"
         @patch="msg">{{ages}}</com>
  </div>
</template>

<script>
import com from './components/com'

export default {
  name: 'app',
  components: {
    com
  },
  data () {
    return {
      ages: 18
    }
  },
  methods: {
    msg: function (ag) { // 父组件接收子组件的参数及其它操作
      this.ages++
      window.console.log(ag)
    }
  }
}
</script>

多组件数据共享: Vuex

我们知道每一个组件都有自己的 data,那么多个组件如何共享数据?这就引出了 state 的概念,可以把多个组件共有的属性统一由state进行管理。但是组件并不能直接访问或操作state里的数据源,而是通过 mutations 来进行如何对数据源进行操作。而改变数据的行为触发由 Actions 来完成,Vue 为 actions的触发提供了一个 commit 的概念,由action 触发通过 mutations 对数据进行操作,从而改变 state 数据源。

那么 vue 的组件(components)如何操作 state 数据源呢?components 通过鼠标、键盘等交互行为触发 (Dispatch) Vuex 的Actions,Actions 对操作进行提交,找到对应的 mutations,进而对 state进行改变。这就是 Vuex 的完整数据流。上代码:

首先,安装 vuex

npm i vuex

新建 store.js

touch src/store.js

Vue中可以存放数据的有组件的 data、computed、props,而state就是放在 computed里。

// store.js

import Vue from 'vue' //引入 vue
import Vuex from 'vuex' // 引入vuex
Vue.use(Vuex) // 将Vue 的全局组件 Vuex 加入到 Vue 的运行框架中

const state = { //数据源
  count: 1
}
const mutations = { //定义数据操作方法
  increment(state) { // 传入数据源
    state.count++ // 操作数据源
  },
  decrement(state) { // 同上
    state.count--
  }
}

// actions 不能直接修改数据, 它会接收 vue 组件的用户行为,进一步触发(commit)操作,由mutations 对数据源state进行修改。补充说明:commit 携带一个参数,这个参数就是 mutations 里的某一个行为,这个行为会对数据源state进行操作,并使vue组件重新render数据变化

const actions = { // 定义数据源操作行为
  increment: ({
    commit
  }) => { // 解构赋值
    commit('increment') // 对应 mutations里的increment,告诉mutations 进行increment 操作
  },
  decrement: ({
    commit
  }) => { // 解构赋值
    commit('decrement') // 对应 mutations里的decrement,告诉mutations 进行decrement 操作
  }
}

// 导出 vuex 的实例
export default new Vuex.Store({
  state,
  mutations,
  actions
})

项目入口文件:

import Vue from 'vue'
import App from './App'
import store from './store' // 引入 store 文件

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store 
// 通过在根实例中注册 store 选项,把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件,子组件可以通过 this.$store 访问
}).$mount('#app')

vue组件(component):

在组件中分发 Actions:

在组件中使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):

// vuex.vue
<template>
  <div class="vuex">
    vuex {{$store.state.count}}
    <!-- 用 $store 取 store 的state数据源 -->
    <button @click="increment">增加</button>
    <button @click="decrement">删减</button>
  </div>
</template>
<script>
import { mapActions } from 'vuex'  // 引入 vuex的 actions
export default {
  methods: mapActions([  // 将methods 映射为 vuex 的 actions
    'increment',
    'decrement'
  ])
}
</script>

延伸:Vuex 模块化

先创建好模块目录及模块文件

mkdir src/store   // 创建 store 目录
mkdir src/store/modules   // 创建store 模块目录
touch src/store/modules/a.js   // 创建 a 模块
touch src/store/modules/b.js  // 创建 b 模块
touch src/store/index.js  // 创建 store 模块入口文件
touch src/components/a.vue   // 创建子组件a
touch src/components/b.vue   // 创建子组件b
// a.js

const state = {
  money: 10
}

const mutations = {
  add(state) {
    state.money++
  },
  reduce(state) {
    state.money--
  }
}

const actions = {
  add: ({
    commit
  }) => {
    commit('add')
  },
  reduce: ({
    commit
  }) => {
    commit('reduce')
  }
}

export default {
  namespaced: true,  //开启命名空间
  state,
  mutations,
  actions
}
// b.js

const state = {
  count: 1
}

const mutations = {
  add(state, param) { // mutations 从 actions 上接收 param 参数并且使用
    state.count += param
  },
  reduce(state) {
    state.count--
  }
}

const actions = {
  add: ({
    commit
  }, param) => { // 这里param参数是从用户交互action行为上接收的参数
    commit('add', param)
  },
  reduce: ({
    commit
  }) => {
    commit('reduce')
  }
}

export default {
  namespaced: true,  //开启命名空间
  state,
  mutations,
  actions
}
// index.js store 入口文件

import Vue from 'vue'    // 引入 vue
import Vuex from 'vuex'   // 引入 vuex
import money from './modules/a'   // 引入模块a
import count from './modules/b'   // 引入模块b

Vue.use(Vuex)   // 引入Vue的全局模块 Vuex

export default new Vuex.Store({
  modules: {   // 导出模块
    money,   // 子模块a
    count    // 子模块b
  }
})
// a.vue

<template>
  <div class="a">
    <!-- 注意:这里从money模块下取state数据 money -->
    page a{{$store.state.money.money}}
    <button @click="add">添加</button>
    <button @click="reduce">删减</button>
  </div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
  methods: mapActions('money', ['add', 'reduce']) 
    // 这里mapActions 接收两个参数,第一个参数是store 子模块名,第二个参数是actions的行为
}
</script>
// b.vue

<template>
  <div class="b">
    <!-- 注意:这里从count模块下取state数据 count-->
    page b{{$store.state.count.count}}
    <!-- 想要mutation 对数据的操作可控,可以在用户交互的 action上传参,在b.js 的actions 接收参数 -->
    <button @click="add(2)">添加</button>
    <button @click="reduce">删减</button>
  </div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
  methods: mapActions('count', ['add', 'reduce'])
    // 这里mapActions 接收两个参数,第一个参数是store 子模块名,第二个参数是actions的行为
}
</script>
// App.vue

<template>
  <div id="app">
    <!--在dom里引入组件a和b-->
    <pagea />
    <pageb />
  </div>
</template>

<script>
import pagea from './components/a' // 引入组件a
import pageb from './components/b' // 引入组件b

export default {
  name: 'app',
  components: {
    pagea, // 注册组件 a
    pageb  //注册组件 b
  }
}
</script>

 

// 项目主入口文件 main.js

import Vue from 'vue'
import App from './App'
import store from './store/index' // 引入 store 模块入口文件

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store // 把Vuex的实例引入Vue实例中
}).$mount('#app')

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值