组件通信

父子组件传值

通过 props 向子组件传递数据

Parent

<template>  <div>    <h1>父给子传值</h1>    <child title="My journey with Vue"></child>  </div></template><script>import child from './Child'export default {  components: {    child  }}</script>

Child

<template>  <div>    <h1>Props Down Child</h1>    <h2>{{ title }}</h2>  </div></template><script>export default {  // props: ['title'],  props: {    title: String  }}</script>

子父组件传值

通过监听子组件事件

Parent

<template>  <div>    <h1>子给父传值</h1>    这里的文字不须要变动    <child :fontSize="hFontSize" @enlargeText="enlargeText"></child>  </div></template><script>import child from './Child'export default {  components: {    child  },  data () {    return {      hFontSize: 1    }  },  methods: {    enlargeText (size) {      this.hFontSize += size    }  }}</script>

Child

<template>  <div>    <h1 :style="{ fontSize: fontSize + 'em' }">Props Down Child</h1>    <button @click="handler">文字增大</button>  </div></template><script>export default {  props: {    fontSize: Number  },  methods: {    handler () {      this.$emit('enlargeText', 0.1)    }  }}</script>

不相干组件传值

通过 EventBus 事件总线

EventBus 又称为事件总线。在 Vue 中能够应用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用雷同的事件核心,能够向该核心注册发送事件或接管事件,所以组件都能够高低平行地告诉其余组件,但也就是太不便所以若应用不慎,就会造成难以保护的“劫难”,因而才须要更欠缺的 Vuex 作为状态管理中心,将告诉的概念回升到共享状态档次。
  • 初始化

首先须要创立事件总线并将其导出,以便其它模块能够应用或者监听它。咱们能够通过两种形式来解决。先来看第一种,新创建一个 .js 文件,比方 eventbus.js

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

另外一种形式,能够间接在我的项目中的 main.js 初始化全局 EventBus

  • 发送事件

当初有两个不相干组件 01 和 02,当 01 组件中对应操作触发 value 变动时发送 numchange 事件

<!-- 01 --><template>  <div>    <h1>不相干组件-01</h1>    <div class="number" @click="sub">-</div>    <input type="text" style="width: 30px; text-align: center;" :value="value">    <div class="number" @click="add">+</div>  </div></template><script>import bus from './eventbus'export default {  props: {    num: Number  },  created () {    this.value = this.num  },  methods: {    sub () {      if (this.value > 1) {        this.value--        bus.$emit('numchange', this.value)      }    },    add () {      this.value++      bus.$emit('numchange', this.value)    }  }}</script><style>.number {  display: inline-block;  cursor: pointer;  width: 20px;  text-align: center;}</style>
  • 接管事件
<!--02--><template>  <div>    <h1>不相干组件-02</h1>    <div>{{ msg }}</div>  </div></template><script>import bus from './eventbus'export default {  data () {    return {      msg: ''    }  },  created () {    bus.$on('numchange', (value) => {      this.msg = `您抉择了${value}件商品`    })  }}</script>

其余通信形式

通过 ref 操作子组件

Parent

<template>  <div>    <h1>ref Parent</h1>    <child ref="c"></child>  </div></template><script>import child from './Child'export default {  components: {    child  },  mounted () {    this.$refs.c.test()    this.$refs.c.value = 'hello input'  }}</script>

Child

<template>  <div>    <h1>ref Child</h1>    <input ref="input" type="text" v-model="value">  </div></template><script>export default {  data () {    return {      value: ''    }  },  methods: {    test () {      this.$refs.input.focus()    }  }}</script>

Vuex

Vuex 是什么?

State

Vuex 应用繁多状态树,用一个对象就蕴含了全副的利用层级状态。

应用 mapState 简化 State 在视图中的应用,mapState 返回计算属性

  • 数组参数
// 该办法是 vuex 提供的,所以应用前要先导入import { mapState } from 'vuex'// mapState 返回名称为 count 和 msg 的计算属性// 在模板中间接应用 count 和 msgcomputed: {  ...mapState(['count', 'msg']),}
  • 对象参数
// 该办法是 vuex 提供的,所以应用前要先导入import { mapState } from 'vuex'// 通过传入对象,能够重命名返回的计算属性// 在模板中间接应用 num 和 messagecomputed: {  ...mapState({    num: state => state.count,    message: state => state.msg  })}

Getter

Getter 就是 store 中的计算属性,应用 mapGetter 简化视图中的应用

import { mapGetter } from 'vuex'computed: {  ...mapGetter(['reverseMsg']),  // 改名,在模板中应用 reverse  ...mapGetter({ reverse: 'reverseMsg' })}

Mutation

更改 Vuex 的 store 中的状态的惟一办法是提交 mutation。Vuex 中的 mutation 十分相似于事件:每
个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是咱们
理论进行状态更改的中央,并且它会承受 state 作为第一个参数

应用 Mutation 扭转状态的益处是,集中的一个地位对状态批改,不论在什么中央批改,都能够追踪到
状态的批改。能够实现高级的 time-travel 调试性能

import { mapMutations } from 'vuex'methods: {  ...mapMutations(['increate']),  // 传对象解决重名的问题 ...mapMutations({ increateMut: 'increate' })}

Action

Action 相似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是间接变更状态。
  • Action 能够蕴含任意异步操作。
import { mapActions } from 'vuex'methods: {  ...mapActions(['increate']),  // 传对象解决重名的问题  ...mapActions({ increateAction: 'increate' }) }

Module

因为应用繁多状态树,利用的所有状态会集中到一个比拟大的对象。当利用变得非常复杂时,store 对
象就有可能变得相当臃肿。

为了解决以上问题,Vuex 容许咱们将 store 宰割成模块(module)。每个模块领有本人的 state、
mutation、action、getter、甚至是嵌套子模块

Vuex 插件

Vuex 的 store 承受 plugins 选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接管 store 作为惟一参数:

在插件中不容许间接批改状态——相似于组件,只能通过提交 mutation 来触发变动。

const myPlugin = store => {  // 当 store 初始化后调用  store.subscribe((mutation, state) => {    // 每次 mutation 之后调用    // mutation 的格局为 { type, payload }  })}// 应用const store = new Vuex.Store({  // ...  plugins: [myPlugin]})

严格模式

在严格模式下,无论何时产生了状态变更且不是由 mutation 函数引起的,将会抛出谬误。这能保障所有的状态变更都能被调试工具跟踪到。

const store = new Vuex.Store({  // ...  strict: true})

模仿实现

  • 实现 install 办法

    • Vuex 是 Vue 的一个插件,先实现 Vue 插件约定的 install 办法
  • 实现 Store 类

    • 实现构造函数,接管 options
    • state 的响应化解决
    • getter 的实现
    • commit、dispatch 办法

install 办法

function install(Vue) {  _Vue = Vue;  _Vue.mixin({    beforeCreate() {      if (this.$options.store) {        _Vue.prototype.$store = this.$options.store;      }    },  });}

Store 类

class Store {  constructor(options) {    const { state = {}, getters = {}, mutations = {}, actions = {} } = options;    this.state = _Vue.observable(state);    this.getters = Object.create(null);    Object.keys(getters).forEach((key) => {      Object.defineProperty(this.getters, key, {        get: () => getters[key](state),      });    });    this._mutations = mutations;    this._actions = actions;  }  commit(type, payload) {    this._mutations[type](this.state, payload);  }  dispatch(type, payload) {    this._actions[type](this, payload);  }}