五个例子带你彻底弄懂vue中组件通讯!

前言

在Vue中,组件通讯主要通过props和events来实现。通过props,父组件可以向子组件传递数据,子组件则通过props接收并使用这些数据。而通过events,子组件可以向父组件发送消息或触发事件,父组件可以监听这些事件并做出响应。

此外,Vue还提供了provide和inject API,允许祖先组件向所有后代组件注入依赖项,而无需显式传递props。这在跨多层次嵌套的组件中特别有用。

今天我们就来聊一聊vue中的组件通讯。

1. 话题引入

我们首先来看一下最原始的一段vue

xml 复制代码
<template>
    <div class="input-group">
        <input type="text" v-model="value">
        <button @click="add">提交</button>
    </div>

    <div>
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>

import { ref } from 'vue'

const list = ref(['html', 'css', 'js'])
let value = ref('')

const add = () => {
    list.value.push(value.value)
    value.value = ''
}



</script>

<style lang="css" scoped>

</style>

这里面的作用很简单,我们通过点击input框可以让列表增加内容。

2.父子组件通讯(父将数据给子)

父子组件通讯 --- 父组件将值v-bind绑定传给子组件,子组件使用defineProps接受

我们文件的大致格式如上,我们这一次的父组件是App1.vue,子组件就是对应的child1.vue.

App1.vue

xml 复制代码
<template>
    <div class="input-group">
        <input type="text" v-model="value">
        <button @click="add">提交</button>
    </div>

    <child :list="list"></child>

</template>

<script setup>

import { ref } from 'vue'
import  child  from '@/components/child1.vue'

const list = ref(['html', 'css', 'js'])
let value = ref('')

const add = () => {
    list.value.push(value.value) 
    value.value = ''
}



</script>

<style lang="css" scoped>

</style>
  1. <child> 组件

    • 将父组件的 list 数组作为属性传递给子组件 <child>
  2. <script setup>

    • 使用 ref 函数创建了两个响应式变量:listvalue
    • list 是一个数组,初始包含三个字符串元素:'html', 'css', 'js'。
    • value 是一个字符串,初始为空。
    • 定义了 add 函数,用于向 list 数组添加新的项,并清空 value

child1.vue

xml 复制代码
<template>
     <div class="child">
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>

defineProps({
    list: {
        type: Array,
        default: () => []
    }
})

</script>

<style lang="css" scoped>

</style>
  1. 模板部分 (<template>)

    • 使用了 Vue 的指令 v-for,遍历 list 数组中的每个 item,并将每个 item 显示为一个 <li> 列表项。
  2. <script setup> 部分

    • 使用了 defineProps 函数,声明了一个名为 list 的 prop。
    • list 的类型被指定为数组 (type: Array),并设置了默认值为空数组 (default: () => [])。
    • 这样做是为了确保 <child> 组件能够正常接收和处理来自父组件的 list 数组数据。

这段代码的大致思路是,首先我们将父组件的list数组传给了子组件,然后子组件以defineProps的形式进行接收,然后进行我们的渲染工作。

App2.vue

xml 复制代码
<template>
    <div class="input-group">
        <input type="text" v-model="value">
        <button @click="add">提交</button>
    </div>

    <child :msg="tochild"></child>

</template>

<script setup>

import { ref } from 'vue'
import  child  from '@/components/child2.vue'

let value = ref('')
let tochild = ref('')
const add = () => {
tochild.value = value.value
}



</script>

<style lang="css" scoped>

</style>

这个 Vue 组件的结构设计了一个简单的输入表单和一个子组件的嵌套。

<template>中:

  • 有一个包含输入框和提交按钮的 .input-group 容器。输入框通过 v-model="value" 实现双向数据绑定,将用户输入的内容同步到 value 变量。
  • 点击按钮时,触发了 add 方法,这个方法将 value 变量的值赋给 tochild 变量。

接着,通过 <child :msg="tochild"></child>tochild 变量的值作为 msg 属性传递给了名为 child 的子组件。

<script setup> 部分:

  • 使用了 Vue 3 的 Composition API 中的 ref 函数来声明了两个响应式变量 valuetochild,它们分别用于存储输入框的内容和传递给子组件的数据。
  • add 函数定义了按钮点击时的行为,将当前输入框中的值赋给 tochild 变量,以便将其传递给子组件。

child2.vue

xml 复制代码
<template>
    <div class="child">
       <ul>
           <li v-for="item in list">{{ item }}</li>
       </ul>
   </div>
</template>

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

const list = ref(['html', 'css', 'js'])

const prop = defineProps({
    msg:''
})

watch(() => prop.msg, (newVal, OldVal) => {
    list.value.push(newVal)
}
)

</script>

<style lang="css" scoped>

</style>

这个 Vue 组件的目的是展示一个简单的列表,列表的内容来自于 list 变量,并且可以接收一个名为 msg 的 prop 属性,将其值添加到列表中。在<template> 中: <ul> 标签用于显示一个无序列表,其中的每个 <li> 标签通过 v-for="item in list" 遍历 list 变量中的每个元素,并将其显示在列表中。

<script setup> 部分:

  • 使用了 Vue 3 的 Composition API 中的 refwatch 函数。
  • list 是一个包含初始值为 ['html', 'css', 'js'] 的响应式数组,用于存储列表中的项目。
  • 使用 defineProps 定义了一个名为 msg 的 prop 属性,允许父组件向当前组件传递数据。
  • watch 函数监听了 prop.msg 的变化,当 msg 属性的值发生变化时,会执行回调函数将新值 newVal 添加到 list 数组中。 这里我们直接让数组归子组件所有,我们直接让父组件传入更新后的值给子组件。

3.子父组件通讯(子将数据给父)

1.子父组件通讯 --- 借助发布订阅机制,子组件负责发布事件并携带参数,父组件订阅该事件通过事件参数获取子组价提供的值

App3.vue

xml 复制代码
<template>
<child @add1="handle"></child>
<div class="child">
       <ul>
           <li v-for="item in list">{{ item }}</li>
       </ul>
   </div>

</template>

<script setup>

import { ref } from 'vue'
import  child  from '@/components/child3.vue'


const list = ref(['html', 'css', 'js'])
const handle = (e) => {
    list.value.push(e)
}



</script>

<style lang="css" scoped>

</style>
  • 使用了 child 组件,并监听了子组件触发的 add1 自定义事件,当事件触发时调用 handle 方法。

  • 显示一个包含动态生成内容的无序列表 (<ul>),使用 v-for="item in list" 循环遍历 list 变量中的每个元素,并在每个 <li> 中显示该元素的内容。

  • 导入了 Vue 3 的 ref 函数,用于声明响应式变量。

  • 定义了 list 变量作为一个响应式数组,初始包含 ['html', 'css', 'js'] 三个元素,用于存储列表显示的内容。

  • 定义了一个 handle 函数,该函数接收一个参数 e,将其作为新的元素添加到 list 数组中。

child3.vue

xml 复制代码
<template>
   <div class="input-group">
        <input type="text" v-model="value">
        <button @click="add">提交</button>
    </div>

</template>

<script setup>

import {ref} from 'vue'

let value = ref('')

const emits = defineEmits(['add1'])

const add = () => {
    emits('add1', value.value)
}

</script>

<style lang="css" scoped>
</style>

在模板部分 (<template>) 中:

  • 包含一个输入框 (<input>) 和一个按钮 (<button>)。
  • 使用了 v-model="value" 来实现双向数据绑定,将输入框中的内容与 value 变量进行绑定,即用户在输入框中输入的内容会同步更新到 value 变量中。
  • 点击按钮时触发 add 方法。

<script setup> 部分:

  • 导入了 Vue 3 的 ref 函数,用于声明一个响应式变量 value,其初始值为空字符串 '',用于存储输入框中的内容。
  • 使用 defineEmits(['add1']) 定义了一个名为 add1 的自定义事件,用于向父组件发送数据。
  • 定义了 add 函数,当按钮被点击时,通过 emits('add1', value.value) 发送 add1 事件,并将当前 value 变量的值作为参数传递给父组件。

2.子父组件通讯 --- 父组件借助v-model将数据绑定给子组件,子组件创建'update:xxx'事件,并接收到的数据修改后emits出来

App4.vue

xml 复制代码
<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 { ref } from 'vue'
    import  child  from '@/components/child4.vue'
    
    let value = ref('')
    const list = ref(['html', 'css', 'js'])
  
    
    
    
    </script>
    
    <style lang="css" scoped>
    
    </style>
  1. 子组件的使用

    • 在模板部分 (<template>) 中,使用了 <child v-model:list="list"></child>,这表示在父组件中将 list 变量作为 child 组件的 v-model 绑定。
    • v-model:list="list" 会将父组件的 list 变量作为一个 prop 传递给 child 组件,并且监听 child 组件触发的更新事件来同步数据。
  2. 列表的渲染

    • 父组件中定义了一个 <div class="child">,其中包含一个无序列表 (<ul>)。

child4.vue

xml 复制代码
<template>
    <div class="input-group">
         <input type="text" v-model="value">
         <button @click="add">提交</button>
     </div>
 
 </template>
 
 <script setup>
 
 import {ref} from 'vue'
 
 let value = ref('')

const prop =  defineProps({
    list: {
        type: Array,
        default: () => []
    }
 })

 const emits = defineEmits(['update:lis'])
 const add = () => {
    // prop.list.push(value.value)
    const arr = prop.list
    arr.push(value.value)
    emits('update:lis',arr)
 }
 

 </script>
 
 <style lang="css" scoped>
 </style>
 
 
  1. 输入框和按钮

    • 在模板部分 (<template>) 中,有一个包含输入框和按钮的 <div>,类名为 input-group
    • 输入框 (<input>) 使用了 v-model="value" 来实现双向数据绑定,即输入框中的内容会与 value 变量同步。
    • 提交按钮 (<button @click="add">提交</button>) 通过点击触发 add 方法。
  2. 脚本部分 (<script setup>) 解释

    • 使用 ref 函数引入 value 变量,初始值为空字符串 '',用于存储输入框中的内容。
    • 使用 defineProps 定义了一个名为 list 的 prop,类型为数组 (Array),默认值为空数组 (() => [])。
    • 使用 defineEmits 定义了一个名为 update:lis 的自定义事件,用于向父组件传递更新后的列表数据。

3.子父组件通讯 --- 父组件通过ref获取子组件中defineExpose() 暴露出来的数据

App5.vue

xml 复制代码
<template>
    <child ref="reff"></child>
    <div class="child">
           <ul>
               <li v-for="item in reff?.list">{{ item }}</li>
           </ul>
       </div>
    
    </template>
    
    <script setup>
    
    import { ref, onMounted } from 'vue'



    import  child  from '@/components/child5.vue'
    
    let value = ref('')

    let reff = ref(null)

  

  
    
    
    
    </script>
    
    <style lang="css" scoped>
    
    </style>
  1. 子组件引用

    • <template> 部分,通过 <child ref="reff"></child> 的方式引入了名为 child 的子组件,并通过 ref="reff" 将子组件实例存储在 reff 变量中,便于后续访问子组件的属性和方法。
  2. 列表展示

    • <template> 中的 <ul> 中,使用 v-for="item in reff?.list" 遍历 reff 引用的子组件中的 list 属性。这里通过 ?. 安全访问操作符,确保在 reff 尚未被初始化之前不会抛出错误。
    • 每个 <li> 标签显示了 item 变量的内容,即子组件中列表中的每个项。
  3. 脚本部分 (<script setup>) 解释

    • 使用 ref 函数声明了 valuereff 变量。value 变量用于存储输入框的内容(在示例中未使用到),reff 变量用于引用子组件的实例。
    • 使用 import child from '@/components/child5.vue' 导入了名为 child 的子组件,在当前组件中可以直接使用它。

child5.vue

xml 复制代码
<template>
    <div class="input-group">
         <input type="text" v-model="value">
         <button @click="add">提交</button>
     </div>
 
 </template>
 
 <script setup>
 
 import {ref} from 'vue'
 
 let value = ref('')

 const list = ref(['html', 'css', 'js'])

 const add = () => {
    list.value.push(value.value)
 }

 
 defineExpose({list:list})

 

 </script>
 
 <style lang="css" scoped>
 </style>
 
 

输入框和按钮位于 <template> 部分。输入框通过 v-model="value" 双向绑定到 value 变量,允许用户输入文本并自动更新 value 的值。按钮通过 @click="add" 绑定了 add 方法,点击按钮时触发 add 方法。

<script setup> 部分,使用 import {ref} from 'vue' 导入 Vue Composition API 的 ref 函数。然后声明了两个响应式变量:

  • value:用于存储输入框中的文本内容,初始值为空字符串。
  • list:用 ref(['html', 'css', 'js']) 初始化为一个包含三个字符串('html', 'css', 'js')的数组。

add 方法定义了一个箭头函数,当按钮被点击时会调用这个函数。它将 value.value 的值(即当前输入框中的文本)添加到 list.value 数组末尾。

相关推荐
编程百晓君2 小时前
一文解释清楚OpenHarmony面向全场景的分布式操作系统
vue.js
暴富的Tdy2 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se2 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
z千鑫2 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js
生产队队长4 小时前
项目练习:element-ui的valid表单验证功能用法
前端·vue.js·ui
web137656076434 小时前
WebStorm 创建一个Vue项目
ide·vue.js·webstorm
秃头女孩y4 小时前
【React中最优雅的异步请求】
javascript·vue.js·react.js
小马哥编程7 小时前
原型链(Prototype Chain)入门
css·vue.js·chrome·node.js·原型模式·chrome devtools
娃哈哈哈哈呀11 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
真滴book理喻14 小时前
Vue(四)
前端·javascript·vue.js