【vue高频面试题—基础篇】:vue 组件通信的方式有哪些

  1. Props 和 Events(父子组件通信)

    • Props(属性传递)

      • 原理 :父组件通过在子组件标签上绑定自定义属性,将数据传递给子组件。子组件通过props选项来接收这些数据。这是一种单向的数据流动,从父组件到子组件,确保了数据的单向性,有助于维护组件的独立性和可预测性。

      • 示例

        • 父组件:
xml 复制代码
<template>
  <child-component :message="parentMessage"></child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: { ChildComponent },
  data() {
    return {
      parentMessage: '这是来自父组件的消息'
    };
  }
};
</script>
  • 子组件:
xml 复制代码
<template>
  <div>{{ message }}</div>
</template>
<script>
export default {
  props: ['message']
};
</script>
  • Events(事件触发)

    • 原理 :子组件通过$emit方法触发自定义事件,将数据或信号传递给父组件。父组件在子组件标签上监听这些事件,并通过事件处理函数来接收和处理数据。这样实现了子组件向父组件的通信。

    • 示例

      • 子组件:
xml 复制代码
<template>
  <button @click="sendMessage">向父组件发送消息</button>
</template>
<script>
export default {
  methods: {
    sendMessage() {
      this.$emit('childMessage', '这是来自子组件的消息');
    }
  }
};
</script>
  • 父组件:
xml 复制代码
<template>
  <child-component @childMessage="handleChildMessage"></child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: { ChildComponent },
  methods: {
    handleChildMessage(message) {
      console.log(message);
    }
  }
};
</script>
  1. 自定义事件总线(非父子组件通信)

    • 原理 :创建一个 Vue 实例作为事件总线,在需要通信的组件中都引入这个事件总线。组件可以通过在事件总线上$emit事件来发送消息,通过在事件总线上$on来监听消息。这种方式可以实现任意两个组件之间的通信,不受父子组件关系的限制。

    • 示例

      • 创建事件总线(通常在main.js或者单独的bus.js文件中):
javascript 复制代码
import Vue from 'vue';
export const eventBus = new Vue();
  • 组件 A 发送消息:
xml 复制代码
<template>
  <button @click="sendMessage">发送消息</button>
</template>
<script>
import { eventBus } from './bus.js';
export default {
  methods: {
    sendMessage() {
      eventBus.$emit('message', '这是来自组件A的消息');
    }
  }
};
</script>
  • 组件 B 接收消息:
xml 复制代码
<template>
  <div>等待接收消息</div>
</template>
<script>
import { eventBus } from './bus.js';
export default {
  created() {
    eventBus.$on('message', this.handleMessage);
  },
  methods: {
    handleMessage(message) {
      console.log(message);
    }
  }
};
</script>
  1. Vuex(状态管理,适用于复杂应用中的组件通信)

    • 原理 :Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。应用的所有组件都可以从 Vuex 的状态树中获取状态,也可以通过提交mutation或者触发action来更新状态。

    • 示例

      • 安装和配置 Vuex(在store/index.js文件中):
javascript 复制代码
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment');
      }, 1000);
    }
  }
});
export default store;
  • 在组件中使用 Vuex:

  • 读取状态:

xml 复制代码
<template>
  <div>计数: {{ count }}</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
  computed: mapState(['count'])
};
</script>
  • 更新状态:
xml 复制代码
<template>
  <button @click="increment">增加计数</button>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
  methods: mapMutations(['increment'])
};
</script>
  1. Provide/Inject(祖先 - 后代组件通信)

    • 原理 :在祖先组件中通过provide选项提供数据或方法,后代组件可以通过inject选项来接收这些数据或方法。这是一种跨层级的组件通信方式,适用于深层嵌套的组件结构,使得深层组件可以方便地获取祖先组件的数据或方法。

    • 示例

      • 祖先组件:
xml 复制代码
<template>
  <div>
    <child-component></child-component>
  </div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: { ChildComponent },
  provide: {
    message: '这是来自祖先组件的消息'
  }
};
</script>
  • 后代组件:
xml 复制代码
<template>
  <div>{{ message }}</div>
</template>
<script>
export default {
  inject: ['message']
};
</script>
  1. Refs 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> p a r e n t 和 parent 和 </math>parent和children

    • Refs(引用组件实例)

      • 原理ref属性用于在父组件中获取子组件的实例引用。通过这个引用,父组件可以直接访问子组件的属性和方法,实现父子组件之间的通信。不过这种方式打破了组件的封装性,应该谨慎使用。

      • 示例

        • 父组件:
xml 复制代码
<template>
  <child-component ref="child"></child-component>
  <button @click="callChildMethod">调用子组件方法</button>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: { ChildComponent },
  methods: {
    callChildMethod() {
      this.$refs.child.childMethod();
    }
  }
};
</script>
  • 子组件:
xml 复制代码
<template>
  <div>子组件内容</div>
</template>
<script>
export default {
  methods: {
    childMethod() {
      console.log('子组件方法被调用');
    }
  }
};
</script>
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> p a r e n t 和 parent 和 </math>parent和children

    • 通过 $parent 可以访问父组件实例,通过 $children 可以访问子组件实例数组。

总结:Props 和 Events(父子组件通信)Provide/Inject(祖先 - 后代组件通信)Vuex(状态管理,适用于复杂应用中的组件通信)自定义事件总线(非父子组件通信)Refs 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> p a r e n t 和 parent 和 </math>parent和children

较大概率引出下面的追问:

1. Props 和 $emit

  • :Props 的单向数据流有什么优势?如何维护数据的一致性?
    :单向数据流保证了数据流向清晰,减少了数据源冲突风险。通过 Vuex 或将共享数据提升到更高的父组件来保持一致性。
  • :如果父组件传递的是深层对象,可能会遇到什么问题?如何优化?
    :可能导致子组件误修改父组件的数据。可以通过浅拷贝传递数据,或使用 Vuex/Pinia 管理共享状态。

2. 兄弟组件通信

  • :事件总线的优缺点是什么?为什么在 Vue 3 中不推荐?
    :事件总线实现简单,耦合低,但难以追踪事件流,容易导致内存泄漏。Vue 3 推荐使用 Vuex、Pinia 或组合式 API 替代。
  • :如何避免事件总线引发的内存泄漏?
    :在组件销毁时,手动移除事件监听,使用 this.$off()onUnmounted

3. Vuex

  • :Vuex 的核心概念有哪些?
    state 存储数据,getters 是计算属性,mutations 用于同步修改状态,actions 用于异步逻辑。
  • :为什么 Vuex 的 state 不能直接修改,只能通过 mutations
    :通过 mutations 修改可被严格追踪和调试,保证状态变化的可预测性。
  • actionsmutations 的区别是什么?
    actions 支持异步操作,mutations 只能同步执行。
  • :Vuex 模块化是如何实现的?
    :通过 modules 分割子模块,设置 namespaced: true 避免命名冲突。

4. Provide/Inject

  • :Provide/Inject 的作用范围是什么?
    :作用于祖先组件到后代组件之间,无需父子直接关系。
  • :Provide/Inject 和 Vuex 的区别是什么?
    :Provide/Inject 适合轻量级依赖注入,不适合复杂的全局状态管理,而 Vuex 更适合集中式管理复杂数据。

5. 全局状态管理

  • :Pinia 相较于 Vuex 有哪些优势?
    :Pinia 提供更简单的 API,更好支持 TypeScript,且不需要手动定义 mutations
  • :Vuex 或 Pinia 的数据是响应式的吗?如何实现的?
    :是的,Pinia 使用 Vue 3 的 reactiveref 实现响应式状态管理。

6. 实际应用场景和经验

  • :在实际项目中,你最常用的通信方式是什么?为什么?
    :常用 props/$emit 处理简单场景,Vuex 管理复杂的全局状态,Provide/Inject 用于组件库开发。
  • :你在组件通信中遇到过哪些难点?如何解决的?
    :共享复杂状态或深层嵌套传递可能混乱,通过 Vuex 模块化管理或组合式 API 提取共享逻辑解决。
  • :项目中是否遇到动态组件加载的通信问题?
    :通过事件总线或 Vuex 存储组件通信的数据,确保动态组件间的数据一致性。
相关推荐
new出一个对象31 分钟前
uniapp-vue2引用了vue-inset-loader插件编译小程序报错
前端·javascript·vue.js
@Autowire1 小时前
请你谈谈:vue的渲染机制(render)- 3举例说明问题
前端·javascript·vue.js
guanyue.space1 小时前
SQL面试50题 数据库准备(存储过程)
数据库·sql·面试
程序员清风2 小时前
RocketMQ负载均衡机制解析!
java·后端·面试
开发那点事儿~2 小时前
vue3实现el-table的拖拽
前端·javascript·vue.js
清酒伴风(面试准备中......)2 小时前
Redis使用场景-缓存-缓存穿透
java·数据库·redis·缓存·面试·实习
针不戳202209262 小时前
嵌入式硬件面试题【经验】总结----会不断添加更新
stm32·单片机·嵌入式硬件·学习·面试
一殊酒3 小时前
【前端开发】JS+Vuew3请求列表数据并分页
前端·javascript·vue.js
景天科技苑3 小时前
【vue-router】Vue-router如何实现路由懒加载
前端·javascript·vue.js·vue-router路由懒加载·vue路由懒加载