Vue.js中关于EventBus的抽像?

场景:

父组件:

<div v-for="(item,index) in corpKideList" :id="item.names" :key="index" :ref="item.names">
      <component :is="item.key"
          :ref="item.key"
          :type="item.key"
          :apply-obj.sync="infoApplyInstance"
          :apply-id.sync="localApplyId"
          @create="showCreatedTimes"
      />
</div>

corpKideList 会有很多数量不定的组件. 这些组件有一些共性的查询,例如:获取字典,加载附件
为了减少子组件对共性的查询次数使用EventBus来合并为一次查询

现在:

获取字典(DictBus),加载附件(AttaBus). 在子组件加载时告诉告诉父组件需要哪些字典项, 组件需要哪些附件. 父组件侦听到当前corpKideList的子组件都加载完开始请求: 字典和附件。获得查询数据后再通过相应的EventBus把结果推到子组件中

BUG:
在多标签页时出现一个问题, 后面新开的标签页(B公司)加载的附件会冲掉已经打开的标签页(A公司)的附件. 发现问题后在原来的事件名中补了一个(公司.id)参数以免冲洗发生. 倒也OK

问题?
由于组件过多,需要一个一个的找到并附加参数, 有什么办法能在EventBus(AttaBus)类上解决此类问题?

阅读 1.6k
2 个回答

一般来说,需要严格执行顺序的场景可以用 EventBus,如果主要为展示数据,应该用 vuex、pinia 等状态管理工具。

对于题主的场景,很明显应该用 vuex/pinia。然后接下来,就可以很方便的利用 vue computed 来获取你要的数据,不需要怎么修改。

在EventBus 中使用唯一标识符,更好的解决方案使用vuex

// EventBus.js
import Vue from 'vue';
export const EventBus = new Vue();

// ParentComponent.vue
<template>
  <div>
    <child-component v-for="(item, index) in items" :key="index" :item="item" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      items: [...] // 你的数据列表
    };
  }
};
</script>

// ChildComponent.vue
<template>
  <!-- 组件内容 -->
</template>

<script>
import { EventBus } from './EventBus';

export default {
  props: ['item'],
  data() {
    return {
      uniqueEventName: ''
    };
  },
  created() {
    this.uniqueEventName = 'attaBus:' + this.item.id; // 使用公司 ID 作为唯一标识符
    EventBus.$on(this.uniqueEventName, this.handleEvent);
    EventBus.$emit('requestAttaBusData', this.uniqueEventName); // 请求数据
  },
  beforeDestroy() {
    EventBus.$off(this.uniqueEventName, this.handleEvent); // 移除事件监听器
  },
  methods: {
    handleEvent(data) {
      // 处理事件数据
    }
  }
};
</script>

Vuex的方法

// store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    requestData: {},
    responseData: {}
  },
  mutations: {
    setRequestData(state, payload) {
      state.requestData[payload.companyId] = payload.data;
    },
    setResponseData(state, payload) {
      state.responseData[payload.companyId] = payload.data;
    }
  },
  actions: {
    async fetchData({ commit, state }, companyId) {
      // 如果响应数据已经存在,则直接返回,不再发起请求
      if (state.responseData[companyId]) {
        return;
      }

      const requestData = state.requestData[companyId];

      // Fetch data from API using requestData
      const data = await api.fetchData(requestData);

      commit('setResponseData', { companyId, data });
    }
  },
  getters: {
    getRequestData: (state) => (companyId) => {
      return state.requestData[companyId];
    },
    getResponseData: (state) => (companyId) => {
      return state.responseData[companyId];
    }
  }
});

父组件

// ParentComponent.vue
<template>
  <div>
    <child-component
      v-for="(item, index) in items"
      :key="index"
      :item="item"
    />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      items: [...] // 你的数据列表
    };
  },
  mounted() {
    this.items.forEach((item) => {
      this.$store.dispatch('fetchDictionary', item.id);
      this.$store.dispatch('fetchAttachments', item.id);
    });
 

子组件内

// ChildComponent.vue
<template>
  <!-- 使用计算属性来获取字典数据和附件数据 -->
  <div>
    <p>Dictionary: {{ dictionaryData }}</p>
    <p>Attachments: {{ attachmentsData }}</p>
  </div>
</template>

<script>
export default {
  props: ['item'],
  computed: {
    // 使用 getters 来获取字典数据和附件数据
    dictionaryData() {
      return this.$store.getters.getDictionary(this.item.id);
    },
    attachmentsData() {
      return this.$store.getters.getAttachments(this.item.id);
    }
  }
};
</script>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏