vue2中实现createStore建立模块级的状态管理

48 阅读1分钟

平时开发业务模块时候,经常遇见需要维护一些模块级别的全局状态等数据。这时候使用 Vuex 等全局状态管理工具,又显得太重( Vuex 管理需要经常变化的数据太麻烦)。这个时候创建一个模块级别的 Store 显得比较重要。可以避免组件间 props 多层传递造成变量重复定义等问题,又使得需要全局管理的状态数据代码从组件中分离出来,可读性更强。

代码实现

使用 Vue.extend 创建一个 Store

// store.js
const Store = Vue.extend({
  data() {
    return {
      states: {
        // 共享数据
      }
    };
  },
  methods: {
    setData(){
      // ...
    }
  }
});

export function createStore(instance, initialState = {}) {
  if (!instance) {
    throw new Error('instance is required.');
  }

  const store = new Store();
  store.instance = instance;
  Object.keys(initialState).forEach(key => {
    store.states[key] = initialState[key];
  });
  return store;
}

// 利用 ES2015 Symbols、函数 `provide` 和对象 `inject`
export const STORE_INJECTION_KEY = Symbol('Store')

父组件中通过 createStore 创建 store 实例,并通过 provide 依赖注入到子/孙组件中

// parent.vue
<template>
  <div></div>
</template>

<script>
import { createStore, STORE_INJECTION_KEY } from './store.js'
export default {
    provide() {
      return {
        [STORE_INJECTION_KEY]: this.store,
      }
    },
    data() {
      const store = createStore(this, {
          // 初始数据
      });
      return {
        store
      };
    }
};
</script>

子/孙组件通过 inject 注入 store

// child.vue
<template>
  <div></div>
</template>

<script>
import { STORE_INJECTION_KEY } from './store.js'
export default {
  inject: {
    store: STORE_INJECTION_KEY
  },
  data() {
    return {};
  },
  created(){
    console.log(this.store.states)
  }
};
</script>

小技巧

一、组件间事件派发

// 组件A emit 一个change事件
this.store.$emit('change', data)

// 组件B listen A组件发出的change事件
this.store.$on('change', data=>{ ... })

二、双向数据绑定

因为注入的 store 是一个响应式对象,所以可以使用 v-model 实现双向绑定。

子组件应当避免直接给全局状态赋值,建议通过 setData 函数修改全局状态

<input v-model="store.states.xxx" />