在vue中,组件A如何调用组件B的方法

刚刚测试人员向我反馈,说这条提交记录审核之后,另一个页签的列表显示没有做状态的同步渲染。
我心想:竟还有这种荒唐事?

好了,废话不多说,直接上菜。这种问题,一眼前端问题(我从前端干到后端,从前台干到后厨 www),大概率就是提交审核接口并完成之后,没有同步去做数据的加载操作了。既然定位到问题所在了,那么解决的思路就很清晰了。

由于我两个页面分别在两个 vue 组件下,称之为组件 A 和组件 B 吧。也就是说,我在组件 A 提交审核之后,没有去再加载一次组件 B 的 loadList 方法,导致列表数据没有重新渲染。在 Vue 中呢,通常有几种方式可以在在一个组件(组件A)中调用另一个组件(组件B)的方法(如loadList),具体取决于组件A和组件B的关系。以下是几种常见的方式:

1、父子组件关系


如果组件A和组件B是父子关系(即组件A是父组件,组件B是子组件),可以通过以下方式调用子组件的方法。

1.1、使用 $refs

可以在父组件中使用ref来引l用子组件实例,然后调用子组件的方法。

<!-- ComponentA.vue -->
<template>
  <div>
    <ChildComponent ref="childRef" />
    <button @click="callChildMethod">Call Child Method</button>
  </div>
</template>

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

export 	default {
  components: {
    ChildComponent
  },
  methods: {
    callChildMethod() {
      this.$refs.childRef.loadList();
    }
  }
}
</script>
<!-- ComponentB.vue -->
<template>
  <div>
    <!-- Child Component Content -->
  </div>
</template>

<script>
export default {
  methods: {
    loadList() {
      console.log('loadList method called');
      // Your logic here
    }
  }
}
</script>

1.2、通过事件总线或 $emit

如果你希望从父组件触发子组件的方法,你也可以通过事件传递。子组件监听一个事件,父组件触发该事件。

<!-- ComponentA.vue -->
<template>
  <div>
    <ChildComponent @triggerLoad="callLoadList" />
    <button @click="emitLoadEvent">Call Child Method via Event</button>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  methods: {
    emitLoadEvent() {
      this.$emit('triggerLoad');
    }
  }
}
</script>
<!-- ComponentB.vue -->
<template>
  <div>
    <!-- Child Component Content -->
  </div>
</template>

<script>
export default {
  methods: {
    loadList() {
      console.log('loadList method called');
      // Your logic here
    }
  },
  mounted() {
    this.$on('triggerLoad', this.loadList);
  }
}
</script>

2、兄弟组件关系


如果组件A和组件B是兄弟组件(即它们都有同一个父组件),你可以通过事件总线或者通过父组件调用的方式来实现。

2.1、使用父组件调用兄弟组件的方法

父组件作为中介来调用一个兄弟组件的方法。

<!-- ParentComponent.vue -->
<template>
  <div>
    <SiblingA @callSiblingB="callSiblingBMethod" />
    <SiblingB ref="siblingBRef" />
  </div>
</template>

<script>
import SiblingA from './SiblingA.vue';
import SiblingB from './SiblingB.vue';

export default {
  components: {
    SiblingA,
    SiblingB
  },
  methods: {
    callSiblingBMethod() {
      this.$refs.siblingBRef.loadList();
    }
  }
}
</script>
<!-- SiblingA.vue -->
<template>
  <div>
    <button @click="$emit('callSiblingB')">Call Sibling B Method</button>
  </div>
</template>

<script>
export default {
}
</script>
<!-- SiblingB.vue -->
<template>
  <div>
    <!-- Sibling B Content -->
  </div>
</template>

<script>
export default {
  methods: {
    loadList() {
      console.log('loadList method called');
      // Your logic here
    }
  }
}
</script>

3、使用事件总线


创建一个全局的事件总线,然后在组件A中发出事件,在组件B中监听事件并调用方法。

// eventBus.js
import Vue from 'vue';
export const EventBus = new Vue();
<!-- ComponentA.vue -->
<template>
  <div>
    <button @click="triggerLoad">Call B's loadList</button>
  </div>
</template>

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

export default {
  methods: {
    triggerLoad() {
      EventBus.$emit('loadList');
    }
  }
}
</script>
<!-- ComponentB.vue -->
<template>
  <div>
    <!-- Component B Content -->
  </div>
</template>

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

export default {
  methods: {
    loadList() {
      console.log('loadList method called');
      // Your logic here
    }
  },
  mounted() {
    EventBus.$on('loadList', this.loadList);
  }
}
</script>

4、我的场景


在我的项目中,组件 A 和组件 B 是存在互相调用的关系的,并且它们之间没有联系。那么可以用事件总线来解决这个问题。
如果组件 A 和组件 B 之间没有直接的父子或兄弟关系,但需要互相调用对方的方法,可以使用事件总线(EventBus)来实现它们之间的通信。这种方式允许在不直接引l用对方的情况下,在组件 A 中调用组件 B 的方法,反之亦然。

  1. 创建一个全新的事件总线
    首先,创建一个全局的事件总线。这个事件总线可以在多个组件之间传递事件。
    // eventBus.js
    import Vue from ‘vue’;
    export const EventBus = new Vue();

  2. 组件 A 监听组件 B 的事件,并调用组件 B 的方法
    在组件A中,当需要调用组件B的方法时,可以通过事件总线发送事件。

<!-- ComponentA.vue -->
<template>
  <div>
    <button @click="callBMethod">Call B's loadList</button>
  </div>
</template>

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

export default {
  methods: {
    loadList() {
      // ...
    },
    callBMethod() {
      // 发送事件通知B去调用B的loadList方法
      EventBus.$emit('loadList')
    }
  },
  mounted() {
    // 监听B发送的事件
    EventBus.$on('loadList', this.loadList);
  },
}
</script>
  1. 组件 B 监听 A 组件的事件,并调用组件 A 的方法
    在组件B中,监听由事件总线发出的事件,当接收到事件时调用自己的方法。
<!-- ComponentB.vue -->
<template>
  <div>
    <!-- Component B Content -->
  </div>
</template>

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

export default {
  methods: {
    loadList() {
      // ...
    },
    callAMethod() {
      // 发送事件通知A去调用A的loadList方法
      EventBus.$emit('loadList')
    }
  },
  mounted() {
    // 监听A发送的事件
    EventBus.$on('loadList', this.loadList);
  },
  beforeDestroy() {
    // 清理事件监听器
    EventBus.$off('loadList', this.loadList);
  }
}
</script>

通过使用事件总线,组件A和组件B可以在没有直接关系的情况下进行互相调用。这种方式非常适合在组件之间需要进行复杂通信但没有直接层级关系时使用。在大型项目中,也可以使用更为复杂的状态管理工具如Vuex来处理这种需求。

可以看到,组件 A 和组件 B 都在各自的 mounted 钩子中监听了 loadList 事件,对于 vue 来说,其实它无法区分调用的是哪个组件下的 loadList,那么 EventBus.$emit('loadList')将会触发 A 组件和 B 组件中的 loadList方法。这是因为事件总线(EventBus)是全局的,这意味着通过 EventBus 发送的事件会被任何监听该事件的组件接收。当你在A组件中调用 EventBus.$emit('loadList')时,任何正在监听loadList 事件的组件都会执行与该事件相关联的方法。

对于这种方法同名的情况,可以采用以下几种方式来区分:

  1. 使用不同的事件名称
    给不同的组件使用不同的事件名称,例如 loadListA 和 loadListB。
    // A组件中监听
    EventBus.$on('loadListA', this.loadList);

// B组件中监听
EventBus.$on('loadListB', this.loadList);
// 在A组件中触发事件
EventBus.$emit('loadListA');

// 在B组件中触发事件
EventBus.$emit('loadListB');

  1. 使用参数区分
    可以通过给 loadList 事件传递一个参数,来区分是哪个组件需要触发该事件。
// A组件中监听
EventBus.$on('loadList', (source) => {
  if (source === 'A') {
    this.loadList();
  }
});

// B组件中监听
EventBus.$on('loadList', (source) => {
  if (source === 'B') {
    this.loadList();
  }
});
// 在A组件中触发事件,传递参数 'A'
EventBus.$emit('loadList', 'A');

// 在B组件中触发事件,传递参数 'B'
EventBus.$emit('loadList', 'B');
  1. 在 beforeDestroy 中解除监听
    如果你只希望某个组件在特定时间段内监听事件,可以在组件销毁前解除监听。
// A组件中监听
EventBus.$on('loadListA', this.loadList);

beforeDestroy() {
  EventBus.$off('loadListA', this.loadList);
}
  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值