剑走偏锋之Vue组件通信(二)——利用provide / inject属性构建全局状态管理

日常咱们的全局状态管理统统都交给Vuex来,Vuex也的确是很是好的工具,并被官方做为指定的状态管理器。今天给你们介绍有个新的思路进行状态管理。可能你们对provide / inject这对api有点陌生,的确也是,日常开发中咱们基本也不会用到。vue

官方 api有这样一句话:这对选项须要一块儿使用,以容许一个祖先组件向其全部子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

看图片能够知道,provide指望传入一个Object,而inject能够接受的值包括(1)一个字符串数组 (2)一个对象。代码以下:(最简单的写法)api

// 父组件 App.vue
export default {
  name: 'App',
  provide: {
    parentKey: 'aaa'
  }
 }

复制代码
// 子组件 chidlren.vue
export default {
  inject: ['parentKey'],
  created () {
    console.log(this.parentKey)
  }
}
复制代码

在打印台能够看到aaa被输出了出来,既然inject指望值是个数组,那应该也能够这样数组

// 父组件 App.vue
export default {
  name: 'App',
  provide: {
    parentKey: { a: 'haha' },
    parentKey2: [1, 2]
  }
 }

复制代码
// 子组件 chidlren.vue
export default {
  inject: ['parentKey', 'parentKey2'],
  created () {
    console.log(this.parentKey, this.parentKey2)
  }
}
复制代码

以前咱们传递是个字符串,发现其实传递什么均可以,对应的对象和数组都打印出来了。 若是仅仅只是这样,好像也没什么。看到api有这样一句话:bash

提示:provideinject绑定并非可响应的。这是刻意为之的。然而,若是你传入了一个可监听的对象,那么其对象的属性仍是可响应的。app

咱们能够试下:iview

// 父组件 App.vue
<template>
  <div class="app">
    <router-view></router-view>
    <button @click="changeKey"> 按钮</button>
  </div>
</template>
export default {
provide () {
    return {
      parentKey: this.key
    }
  },
  methods: {
    changeKey () {
      this.key.push(2)
    }
  },
  data () {
    return {
      key: [1]
    }
  }
 }
复制代码
// 子组件 chidlren.vue
export default {
  inject: ['parentKey'],
  created () {
    let afterKey = JSON.stringify(this.parentKey)
    let timer = setInterval(() => {
      console.log(this.parentKey)
      if (afterKey !== JSON.stringify(this.parentKey)) clearInterval(timer)
    }, 1000)
  }
 }
复制代码

最后能够看见当点击按钮以后,在子组件chidlren.vue中输出的值变化了,定时器也中止了。ide

这里面有几个要注意的地方 (1). 这时候provide必须为一个工厂函数,若是你是这样写的provide: {parentKey: this.key}也就是跟以前这种写法,控制台会报未定义key的错误 (2)不要传字符串之类的值过去,好比:parentKey: this.key 而你在data中是这样定义keykey: 'aaa,提示下,他并非一个可响应的数据,你可能会说,那不对啊,我在当前组件改变这个值,模板里输出的也会变啊。这时候其实可响应的值是this当前组件 (3)你们不要试图替换数组来响应(为何说这条,由于不注意我也犯了这个错误 :) (4)一旦注入了某个数据,好比上面示例中的 parentKey,那这个组件中就不能再声明 parentKey 这个数据了,由于它已经被父级占有)函数

注意:在变异 (不是替换) 对象或数组时,旧值将与新值相同,由于它们的引用指向同一个对象/数组。Vue 不会保留变异以前值的副本。(来源Vue官网)工具

好像说了这么久,没说到与标题相关的。:)-- 接下来久介绍下构建全局状态管理的思路网站

// 父组件(也能够说是根组件) App.vue
export default {
  name: 'App',
  provide () {
    return {
      app: this
    }
  },
  methods: {
    changeKey () {
      this.key.push(2)
    }
  },
  data () {
    return {
      key: [1],
      transitionName: 'slide-right'
    }
  }
}

复制代码
// 子组件 chidlren.vue
export default {
  inject: ['app'],
  created () {
    console.log(this.app)
    console.log(this.app.key)
    this.app.changeKey()
  }
}
复制代码

这样你就能够拿到根节点app全部的东西了,还能够访问他的方法。以此将根节点做为状态管理器。 若是你以为这样状态多起来,十分难管理,你可使用混合mixins,将不一样的逻辑分开到不一样的 js 文件里。固然这种事是仁者见仁智者见智,你可使用this.$root访问根节点,还能够挂载在Vue.prototype的原型上。哈哈,这些方法是否是感受有点邪门歪道的感受。因此官网有这么一句话:

provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

给你们介绍下这个网站dev.iviewui.com,这个网站就是使用此方法作出来的,这样减小了Vuex的依赖使用vue自己做为状态管理器,固然,若是你的网站很大,仍是建议使用Vuex

这对api还有不少东西能够挖掘的,好比使用ES2015的Symbol做为惟一值,inject中可使用default做为默认值等等。用法仍是同窗们去看看官网。此次久到此为止,清明放假了,仍是休息休息。:)

若有错误,欢迎指出。

相关文章
相关标签/搜索