MST

星途 面试题库

面试题:Vue中父子组件通信方式对比及应用场景

请详细阐述Vue中父子组件通信常用的props和$emit方式的原理,并举例说明在哪些实际业务场景下会优先选择props,哪些场景下优先选择$emit进行父子组件间的数据传递与交互。
35.3万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

props原理

  1. 单向数据流:在Vue中,props是父组件向子组件传递数据的主要方式。父组件通过在子组件标签上以属性的形式绑定数据,子组件通过props选项声明接收这些数据。这种传递是单向的,即父组件数据变化会自动更新子组件,而子组件不能直接修改父组件传递过来的props数据,以防止数据流向混乱。
  2. 数据响应式:Vue利用其响应式系统,当父组件中绑定到props的数据源发生变化时,Vue会检测到变化并重新渲染使用该props的子组件,保证子组件展示数据的实时性。

$emit原理

  1. 自定义事件机制:$emit是子组件向父组件传递数据或触发事件的方式。子组件通过$emit方法触发一个自定义事件,并可以携带数据作为参数。父组件在子组件标签上通过v-on指令监听这个自定义事件,当子组件触发该事件时,父组件中对应的事件处理函数会被调用,并接收子组件传递过来的数据。
  2. 事件冒泡:这种机制类似于原生DOM事件的冒泡机制,使得子组件的操作能够通知到父组件,实现父子组件间的交互。

优先选择props的业务场景

  1. 展示型组件:例如一个UserInfo子组件用于展示用户信息,父组件拥有用户的基本数据(如姓名、年龄等),此时父组件通过props将用户数据传递给UserInfo组件进行展示。这样可以保证数据的单向流动,数据的控制权在父组件,子组件只专注于展示。
<template>
  <div>
    <UserInfo :user="userData" />
  </div>
</template>
<script>
import UserInfo from './UserInfo.vue';
export default {
  components: {
    UserInfo
  },
  data() {
    return {
      userData: {
        name: 'John',
        age: 30
      }
    };
  }
};
</script>
  1. 配置型组件:如一个Button子组件,父组件可以通过props传递按钮的文本、样式、是否禁用等配置信息。
<template>
  <div>
    <Button :text="buttonText" :disabled="isButtonDisabled" />
  </div>
</template>
<script>
import Button from './Button.vue';
export default {
  components: {
    Button
  },
  data() {
    return {
      buttonText: 'Click Me',
      isButtonDisabled: false
    };
  }
};
</script>

优先选择$emit的业务场景

  1. 用户交互反馈:比如在一个Input子组件中,用户输入内容后,子组件需要将输入的值反馈给父组件进行进一步处理(如提交表单等)。子组件通过$emit触发一个自定义事件并传递输入值,父组件监听该事件并接收数据。
<template>
  <div>
    <Input @input-change="handleInputChange" />
  </div>
</template>
<script>
import Input from './Input.vue';
export default {
  components: {
    Input
  },
  methods: {
    handleInputChange(value) {
      console.log('Received input value:', value);
      // 进行后续处理,如提交表单等
    }
  }
};
</script>
  1. 子组件状态改变通知:假设一个Dropdown子组件,当用户点击展开或收起时,子组件需要通知父组件其展开状态的变化。子组件通过$emit触发事件告知父组件,父组件可以根据这个状态进行其他操作(如显示遮罩层等)。
<template>
  <div>
    <Dropdown @toggle="handleDropdownToggle" />
  </div>
</template>
<script>
import Dropdown from './Dropdown.vue';
export default {
  components: {
    Dropdown
  },
  methods: {
    handleDropdownToggle(isOpen) {
      console.log('Dropdown is', isOpen? 'open' : 'closed');
      // 根据展开状态进行其他操作
    }
  }
};
</script>