toFrankie / blog

种一棵树,最好的时间是十年前。其次,是现在。
22 stars 1 forks source link

Vue 组件之间通信以及状态管理模式(Vuex) #191

Open toFrankie opened 1 year ago

toFrankie commented 1 year ago

一、使用 props

props 用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义校验和设置默认值。这种方式,不能在子组件更改父组件的对应的属性值

<!-- 父组件 -->
<template>
  <child message="这是父组件给子组件的信息"></child>
</template>

<script>
import Child from '../xxx/xxx'
export default {
  components: { Child }
}
</script>
<!-- 子组件 -->
<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  props: ['message']
}
</script>

props 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态。

若一定要改,只能通过子组件 $emit(),父组件 $on() 进行响应更改,如在更复杂的情况下,建议使用状态管理模式,即 Vuex。下面会讲述这两种方式的具体使用方式。

二、\$emit()、$on() 非父子组件间的通信(简单场景)

$emit()$on()和的事件必须是在一个公共的实例上,才能触发。官方文档里这个主要用于非父子组件之间的通信。

下面对这个例子简单修改一下:

// 新建一个公共示例
// bus.js
import Vue from 'vue'
export const bus = new Vue()
<!-- 父组件 -->
<template>
  <child :message="message"></child>
</template>

<script>
import Child from '../xxx/xxx'
// 引入公共实例
import { bus } = from 'xxx/bus.js'
export default {
    components: {Child},
    data() {
      return {
         message: '这是父组件给子组件的信息'
      }
    },
  mounted() {
    // $on() 响应
    bus.$on('change', (msg) => {
      console.log(msg)
    })
  }
}
</script>
<!-- 子组件 -->
<template>
  <div>{{ message }}</div>
</template>

<script>
import { bus } from 'xxx/bus.js'
export default {
  props: ['message'],
  watch: {
    message(newVal, oldVal) {
      // 通过 $emit() 去触发
      bus.$emit('change', '要改变的值')
    }
  }
}
</script>

三、使用 Vuex 进行状态管理(主要用于较为复杂场景),划重点

  1. 安装 Vuex
    npm install vuex --save
  2. 新建 store.js ,将 Vuex 放在里面,我就不放 main.js 里了
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

/**
 * 说明:
 *
 * 一、Mutations
 * 1. 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
 * 2. 一条重要的原则就是要记住 mutation 必须是同步函数
 *
 * 二、Action
 * 1. action 提交的是 mutation,而不是直接变更状态
 * 2. action 可以包含任意异步操作
 * 3. 所以我更喜欢使用 action 去提交 mutation,例如下面这个异步操作
 *
 */

const store = new Vuex.Store({
  // 定义状态
  state: {
    message: ''
  },
  mutations: {
    changeMessage(state, payload) {
      // 状态变更
      state.message = payload
    }
  },
  actions: {
    changeMessage(context, args) {
      context.commit('changeMessage', args)
      setTimeout(() => {
        // 1.5s 后置空
        context.commit('changeMessage', '')
      }, 1500)
    }
  }
})

export default store

3). main.js 引入

import Vue from 'vue'
import App from './App.vue'
import store from './store.js'

new Vue({
  el: '#app',
  store,
  render: h => h(App)
})

4). 提交载荷、分发 Action、获取状态

// 以下 this 指向 vue 实例

// 提交 Payload,仅支持同步操作
this.$store.commit('changeMessage', 'any')

// 分发 Action,支持异步操作
this.$store.dispatch('changeMessage', 'any')

// 获取 state
const var1 = this.$store.state.message

写得有点啰嗦了,更具体或者细节的地方,麻烦移步官方文档: Vuex 是什么?

啊啊啊,不想写了,好了,就到此为止吧。有疑问的留意,尽我所会的回答。(如有更好的方式,或者改进的地方,欢迎指出!)