likes
comments
collection
share

面试官:请你聊聊Vue中常见的组件通信方式。

作者站长头像
站长
· 阅读数 23

前言

在Vue中组件通信是最强大的功能之一,但是组件的作用域是相互独立的,意味着不同组件之间的数据无法相互进行直接的引用,所以组件之间的通信非常重要。

常见的几种组件通信方式

父组件通过 props 向子组件传递数据,子组件通过 emit 和父组件通信。

1. Props(父传子)

  • 定义:Props 是父组件向子组件传递数据的一种方式。父组件通过在子组件标签上设置属性的方式来传递数据,子组件则通过 props 选项来声明它预期接收的数据。

  • 使用方法

    • 父组件:在子组件标签上绑定变量或表达式。

    <!-- 父组件 -->
    <template>
      <ChildComponent :message="parentMessage" />
    </template>
    <script>
    import ChildComponent from './ChildComponent.vue';
    export default {
      components: { ChildComponent },
      data() {
        return {
          parentMessage: 'Hello from Parent'
        };
      }
    };
    </script>
  • 子组件:在 props 选项中声明期望接收的属性。
     // 子组件
    export default {
    props: ['message'],
    mounted() {
    console.log(this.message); // 输出: Hello from Parent
    }
    };

2. emit (子传父)

  • 定义:当需要从子组件向父组件传递数据或事件时,可以使用 Vue 的自定义事件系统。子组件通过 emit 方法触发一个事件,并可以携带数据,父组件则监听这个事件。

  • 使用方法

    • 子组件:触发一个自定义事件,并传递数据(如果需要)。
<script setup>
    const emits = defineEmits(["child-event"]);//创建一个事件
   onMounted() => {
    //给到父组件
    emits("child-event", 'hello')//发布事件
}

</script>
  • 父组件:在模板中使用 v-on 或简写的 @ 监听子组件的事件。
    <template>
        <ChildComponent @child-event="parentMethod" />
    </template>
    <script>
    // ...
    methods: {
        parentMethod(dataFromChild) {
            console.log(dataFromChild); // 处理子组件传递过来的数据 hello
          }
        }
   </script>

3. v-model双向数据绑定(子传父)

  • 子组件
<template>
    <div class="input-group">
        <input type="text" v-model="value">
        <button @click="add">添加</button>
    </div>
</template>

<script setup>
import {ref} from "vue"
const value=ref(" ")

const props=defineProps({
    list:{
        type:Array,
        default:()=>[]
    }
})
const emits=defineEmits(["update:list"])
const add=()=>{
    //props.list.push(value.value)  //不建议直接操作父组件给过来的数据
    const arr =props.list;
    arr.push(value.value)
    emits("update:list",arr)//抛出来修改后的数组,在父组件中有v-model: 会促使它去修改数据
}

</script>

<style lang="css" scoped>

</style>
  1. 接收数据:子组件通过 defineProps 接收来自父组件的 list 数据,类型为数组。
  2. 定义事件:使用 defineEmits 定义了一个名为 "update:list" 的自定义事件,用于通知父组件更新 list
  3. 数据绑定与修改:子组件内部使用 v-model 绑定了一个局部响应式变量 value 到输入框,初始值为空字符串。用户在输入框中输入文本时,value 的值会随之改变。
  4. 按钮点击事件:当用户点击“添加”按钮时,触发 add 方法。此方法中,首先创建了一个父组件 list 的副本 arr,然后将 value 的值添加到 arr 中。接着,通过 emits("update:list", arr) 触发自定义事件,并将修改后的数组作为参数传递给父组件。
  5. 父组件响应:父组件监听到 update:list 事件后,会自动更新其 list 的值,从而导致页面上显示的列表项更新,新增了用户输入的文本。
  • 父组件
<template>
    
    <Child v-model:list="list"></Child>
    <div class="child">
        <ul>
            <li v-for="item in list">
                {{ item }}
            </li>
        </ul>
    </div>
</template>

<script setup>
import Child from "@/components/child3.vue";
import { ref } from "vue"
const list = ref(["html", "css", "js"])

</script>

<style lang="css" scoped></style>
  1. 数据初始化:父组件使用 ref 创建了一个响应式数组 list,初始值为 ["html", "css", "js"]
  2. 子组件使用:通过 v-model:list 指令将 list 绑定到子组件 Child 上。这里 v-model 是一个语法糖,实际上绑定了 list 作为 prop (list) 并监听 update:list 事件来更新 list 的值。由于 v-model 默认对应 value prop 和 input 事件,但在这里通过 model 属性显式指定了使用 list prop 和对应的事件名称 update:list

整个过程中,子组件通过自定义事件将修改后的数据通知给父组件,父组件利用 v-model 的特性自动处理了数据的更新,实现了数据的双向绑定。注意子组件中直接操作 props 的做法是不推荐的,因此通过创建 arr 副本来避免直接修改父组件传递的数据。

4. defineExpose暴露数据 (子传父)

  • 子组件
<template>
    <div>
        <p>{{ message }}</p>
        <button @click="incrementCounter">点击增加计数</button>
    </div>
</template>

<script setup>
import { ref, defineExpose } from 'vue';

const message = ref('你好,我是子组件');
const counter = ref(0);

const incrementCounter = () => {
  counter.value++;
};

// 使用 defineExpose 暴露 message 和 incrementCounter 给父组件
defineExpose({
  message,
  incrementCounter
});
</script>

在这个子组件中,我们定义了两个响应式数据:message 和 counter,以及一个方法 incrementCounter。通过 defineExpose,我们将 message 和 incrementCounter 暴露给父组件。

  • 父组件
<template>
    <div>
        <ChildComponent ref="childRef" />
        <button @click="displayMessage">显示子组件消息</button>
        <button @click="increaseCounter">调用子组件方法增加计数</button>
    </div>
</template>

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

const childRef = ref(null);

const displayMessage = () => {
  alert(childRef.value.message);
};

const increaseCounter = () => {
  childRef.value.incrementCounter();
};
</script>

在父组件中,我们首先通过模板引用 ref="childRef" 获取了子组件的实例。然后,定义了两个按钮,分别调用 displayMessage 和 increaseCounter 方法。这两个方法通过 childRef.value 访问到了子组件暴露出来的 message 和 incrementCounter

本篇文章就到此为止啦,希望通过这篇文章能对你理解Vue组件通信有所帮助,本人水平有限难免会有纰漏,欢迎大家指正。如觉得这篇文章对你有帮助的话,欢迎点赞收藏加关注,感谢支持🌹🌹。

面试官:请你聊聊Vue中常见的组件通信方式。

转载自:https://juejin.cn/post/7385752495535964175
评论
请登录