vue3-父子组件间通信

这篇具有很好参考价值的文章主要介绍了vue3-父子组件间通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在实际业务开发的过程中,我们时常会遇到组件间的通信问题,比如:父子组件间通信、同级组件间通信等。本篇文章中主要介绍父子组件间通信。父子组件间通信主要有以下常见形式:

方案 父组件向子组件 子组件向父组件
props/emits props emits
v-model/emits v-model emits
ref/emits ref emits

不再说明!!!父组件->Parent.vue;子组件->Children.vue,并且代码主要展示template和script部分

方案一:props/emits

  props/emits是最常用的形式,也是最基础的方案。其主要过程是:
1、父组件->子组件:子组件先定义props对象并渲染到标签里,然后在父组件中调用子组件,通过属性的方式“: 变量名= ”绑定在标签上。
2、子组件->父组件:父组件先声明数据变量和更新函数然后通过“@函数名= ”绑定事件,然后子组件通过emits向父组件发送更新信号,一般伴随着数据变量。

props:父组件->子组件

首先要在子组件Children.vue定义props对象并且使用。我们先来看一下下面的代码:

// Children.vue
<script>
export default defineComponent({
  // props: ['title', 'index', 'userName', 'uid']
  props: {
    // 可选,并提供默认值
    title: {
      type: String,
      required: false,
      default: '默认标题',
    },
    // 默认可选,单类型
    index: Number,
    // 添加一些自定义校验
    userName: {
      type: String,
      // 在这里校验用户名必须至少 3 个字
      validator: (v) => v.length >= 3,
    },
    // 默认可选,但允许多种类型
    uid: [Number, String],
  },
  // 在这里需要添加一个入参
  setup(props) {
    // 该入参包含了当前组件定义的所有 props
    console.log(props)
  },
})
</script>

<template>
  // 渲染父组件传递过来的值
  <p>标题:{{ title }}</p>
  <p>索引:{{ index }}</p>
  <p>用户id:{{ uid }}</p>
  <p>用户名:{{ userName }}</p>
</template>

  虽然可以将变量一并装在一个string[]数组里,但是更推荐封装在对象里,因为vue3支持对props进行类型限制和一些配置,这样在实际开发中不会造成格式混乱。如果传入不正确的类型,会抛出警告信息。例如父组件向子组件传递一个日期,如果不做类型限制的话可能会导致页面渲染失败。
其中支持的类型有:

类型 含义
String 字符串
Array 数组
Boolen 布尔值
Object 对象
Date 日期
Function 函数;例如:钩子函数、箭头函数和普通函数等
Promise Promise类型的函数
Symbol Symbol类型的值

支持的配置选项有:

选项 类型 含义
type string 类型
required boolean 是否必传,true是必传,false为可传
default any 与type类型相对应的默认值。若required为false但不设置默认值,则默认为undefined
validator function 自定义验证函数,需要return一个布尔值,true为校验通过,false为校验不通过。校验不通过时,控制台会抛出警告信息

然后在父组件Parent.vue中调用子组件,通过属性的方式“: 变量名= ”绑定在标签上。来看以下代码:

// Parent.vue
<script>
import { defineComponent } from 'vue'
// 引入子组件Children.vue
import Children from '@./Children.vue'
interface Member {
  id: number
  name: string
}
export default defineComponent({
  // 需要启用子组件作为模板
  components: {
    Children,
  },
  setup() {
    const userInfo: Member = {
      id: 1,
      name: 'Petter',
    }
    return {
      userInfo,
    }
  },
})
</script>

<template>
  <Children
    title="用户信息"
    :index="1"
    :uid="userInfo.id"
    :user-name="userInfo.name"
  />
</template>

emits:子组件->父组件

首先父组件Parent.vue声明数据变量和定义更新函数然后通过“@事件名称=更新函数 ”绑定事件。看下面代码:

// Parent.vue
<script>
import { defineComponent, reactive } from 'vue'
import Children from '@./Children.vue'
interface Member {
  id: number
  name: string
  age: number
}
export default defineComponent({
  components: {
    Children,
  },
  setup() {
    const userInfo: Member = reactive({
      id: 1,
      name: 'Petter',
      age: 0,
    })
    /**
     * 声明一个更新年龄的方法
     * @param name, age - 新的名字和新的年龄,由子组件触发 emits 时向父组件发送信号
     */
    function updateInfo({ name, age }: Member) {
  		// 当 `name` 变化时更新 `name` 的值
  		if (name && name !== userInfo.name) {
    		userInfo.name = name
  		}
  		// 当 `age` 变化并且新值在正确的范围内时,更新 `age` 的值
  		if (age > 0 && age !== userInfo.age) {
    		userInfo.age = age
  		}
  		// 显示新的名字和新的年龄
  		alert({ name, age })
	},
    return {
      userInfo,
      updateInfo,
    }
  },
})
</script>

<template>
  <Child @update-info="updateInfo" />
</template>

然后子组件Children.vue通过emits向父组件发送更新信号,一般伴随着数据变量。来看下面代码:

// Children.vue
<script>
export default defineComponent({
  // emits: ['update-info']
  // 先定义emits对象
  emits: {
    // 需要校验
    'update-info': (name: string, age: number) => {
      // 写一些条件拦截,返回 `false` 表示验证不通过
      if (age < 18) {
        console.log('未成年人不允许参与')
        return false
      }
      // 通过则返回 `true`
      return true
    },
    // 若无需校验的,设置为 `null` 即可。例如:'update-name': null
  },
  // 使用 setup 第二个参数 context 里的 emit 方法触发
  setup(props, { emit }) {
    // 通知父组件将年龄设置为 `18`和将姓名设置为`Tom`
    emit('update-info', {
  		name: 'Tom',
  		age: 18,
	})
  },
})
</scirpt>

<template>
	<div @click="undate-info">发送给父组件</div>
</template>

  和 props 一样,可以指定是一个数组,把要接收的 emit 事件名称写进去;但是相同的使用对象可以更好管理数据。emits最少要传递一个参数:事件名称。事件名称是在子组件书写。
  上述代码的事件名称是指父组件 Parent.vue 绑定事件时 @update-info=“updateInfo” 里的 update-info ,如果改成 @hello=“updateInfo” ,那么事件名称就需要使用 hello ,一般情况下事件名称和更新函数的名称会保持一致,方便维护。
  同时,emits也支持传递多个参数,第二个参数可以使用对象修饰数据。
  emits可以进行一些校验操作,方法如下emits:{ 事件名称(key): 函数(val) => { return 布尔值 }},详情看上述代码。

TIPS:
1、官方文档推荐对 camelCase 风格(小驼峰)命名的 props 和emits,但在绑定时使用和 HTML attribute 一样的 kebab-case 风格(短横线),例如使用 user-name 代替 userName 传递,详见官网的传递 props和emits的细节 一节。

方案二:v-model/ emits

  事实上,v-model与props的配置差不多,那为什么要用v-model呢?主要体现在父组件->子组件上。
  在上述的讲解中可以看出,方案props/emits中,子组件向父组件传递数据,父组件必须声明一个更新函数并绑定事件给子组件,才能更新数据。而使用方案v-model/emits则无需父组件声明函数就能更新数据。具体改动如下:

// Parent.vue
<template>
  <Children
    v-model:uid="userInfo.id"
    v-model:username="userInfo.name"
    v-model:age="userInfo.age"
  />
</template>
<script>
import { defineComponent, reactive } from 'vue'
import Children from '@./Children.vue'
interface Member {
  id: number
  name: string
  age: number
}
export default defineComponent({
  setup() {
    // 通知父组件将年龄设置为 `18`和将姓名设置为`Tom`
    const userInfo: Member = reactive({
      id: 1,
      name: 'Petter',
      age: 0,
    }),
    onMounted( () => {
      console.log(userInfo.id, userInfo.name,userInfo.age)
    }),
    return userInfo
  },
})
</script>

想要绑定多个数据,可以使用多个v-model;
格式:<组件 v-model: 子组件中定义的变量名称=父组件定义的变量名称></组件>

// Children.vue
<script>
export default defineComponent({
  props: {
    uid: Number,
    username: String,
    age: Number,
  },
  // 注意这里的 `update:` 前缀
  emits: ['update:uid', 'update:username', 'update:age'],
})
</script>
<template>
  // 渲染父组件传递过来的值
  <p>用户id:{{ uid }}</p>
  <p>用户名:{{ username }}</p>
  <p>年龄:{{ age }}</p>
</template>

子组件中emits属性格式需要转变成:emits: [update: 父组件v-model属性名/子组件定义的变量名称。]

方案三:ref/emits

  props和v-model主要是值的传递,而使用ref还可以操作子组件的方法

  除了方案一、二之外,我们还可以使用方案三ref/emits。主要改动也是体现在父组件->子组件上,且进一步简化了操作。我们只需要在父组件上声明一个响应式对象,而无需再像上面两个方案上一样,需要父组件调用子组件时在子组件上绑定一个ref属性,然后就能对子组件的属性和方法进行操作,这样会简化代码。具体操作如下:
  首先,子组件上声明响应式变量,然后在setup函数内return变量。只有return了父组件才能调用,否则父组件无法获取。

// Children.vue
<template>
  // 渲染从父组件Parent.vue接受到的值
  <div> Children: {{ valueRef }}</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
  name: 'Children',
  setup() {
    const valueRef = ref('')
    // 该函数可以接受父级传递一个参数,并修改valueRef的值
    const acceptValue = (value: string) => (valueRef.value = value)
    return {
      acceptValue,
      valueRef
    }
  }
})
</script>

  然后父组件Parent.vue使用空的响应式对象来操作子组件的响应式对象,并且调用子组件时在其标签上绑定ref属性。

// Parent.vue
<template>
  <div>childrenRef</div>
  <button @click="sendValue">send</button>
  // 这里ref接受的字符串,要setup返回的ref类型的变量同名
  <Children ref="childrenRef" />
</template>
 
<script lang="ts">
import { defineComponent, ref } from 'vue'
import Children from './Children.vue'
export default defineComponent({
  name: 'Parent',
  components: {
    Children
  },
  setup() {
    // 如果ref初始值是一个空,可以用于接受一个实例
    // vue3中获取实例的方式和vue2略有不同
    const childrenRef = ref<typeof Children>()
    // 请保证视图渲染完毕后再执行操作
    onMounted( () => {
      // 可以拿到Children组件实例,并调用其setup返回的所有信息
      console.log(childrenRef.value)
      // 通过调用子组件实例的方法,向其传递数据
      childrenRef.value.acceptValue('123456')
      // 也可以去操作子组件的数据
      childrenRef.value.valueRef = '8888';
    });
 
    // 必须return出去才可以给到template使用
    return {
      childrenRef, 
    }
  }
})
</script>

  ref()其实是将变量变成一个对象,以键值对存储{ 变量名key:值value}。子组件实例本身就以键值对形式存储,而子组件中的响应式对象的存储形式又是键值对,故父组件调用子组件的响应式对象的格式是:响应式对象.value.子组件响应式对象。
  emits的改动请参考方案二。

应用场景

知道原理后,我们要回到实际开发应用中去:一般情况下
1、父组件->子组件:父组件发起 AJAX 请求,拿到数据后,再根据子组件的渲染需要传递不同的 props 给不同的子组件使用。
2、子组件->父组件:更新表单等数据量较多时非常好用。文章来源地址https://www.toymoban.com/news/detail-754084.html

到了这里,关于vue3-父子组件间通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue3探索——使用ref与$parent实现父子组件间通信

    在vue3中,可以使用vue3的API defineExpose() 函数结合 ref 或者 $parent ,实现父子组件数据的传递。 子组件:通过 defineExpose() 函数,向外暴露响应式数据或者方法 父组件:通过 ref 获取子组件实例,进而获取子组件暴露的响应式数据或方法 💡 你没看错!这里的 ref 就是经常用来定

    2024年02月10日
    浏览(42)
  • Web前端 ---- 【Vue】(组件)父子组件之间的通信一文带你了解

    目录 前言 父组件传子组件 ---- props 给要传递数据的子组件绑定要传过去的属性及属性值 在子组件中使用props配置项接收 props配置项 子组件传父组件 ---- 组件的自定义事件 子组件向父组件传递数据 通过代码来绑定自定义事件 本文将介绍在Vue中父子组件如何进行通信 这里先介

    2024年02月05日
    浏览(117)
  • Vue3的手脚架使用和组件父子间通信-插槽(Options API)学习笔记

    全局安装最新vue3 升级Vue CLI: 如果是比较旧的版本,可以通过下面命令来升级 通过脚手架创建项目 父组件 子组件 UserComponent.vue 父组件 **子组件1 JiaComponent.vue ** ** 子组件2 JianComponent.vue ** 父组件 子组件 TitleComponents.vue 父组件 **子组件 NavComponent.vue ** 父组件 子组件 NavCompone

    2024年02月05日
    浏览(42)
  • vue3中监听,组件通信如父子传值、Vuex、Event Bus的使用

    目录 一、监听 二、父子传值: 1、父传子: 2、子传父 三、全局状态管理(Vuex): 四、事件总线(Event Bus): 我们有一个父组件ParentComponent和一个子组件ChildComponent。在父组件中,我们使用:childProp=\\\"parentData\\\"将数据传递给子组件。在子组件中,我们使用defineProps来接收父组件

    2024年02月13日
    浏览(40)
  • Vue组件通信——父子组件通信的四种方法

    全局引入 在main.js文件中引入并注册 之后就可以全局使用组件了 局部引入 在父组件中引入 之后就可以在父组件中使用组件了 在子组件 prop 中可以注册一些自定义组件属性,父组件调用子组件时可以向 prop 中的自定义属性传值。 子组件代码: 父组件代码 prop 也可以通过 v-

    2023年04月16日
    浏览(104)
  • Vue中父子组件通信

    聚沙成塔·每天进步一点点 Vue学习之旅的奇妙世界 欢迎大家来到 Vue 技能树参考资料专栏!创建这个专栏的初衷是为了帮助大家更好地应对 Vue.js 技能树的学习。每篇文章都致力于提供清晰、深入的参考资料,让你能够更轻松、更自信地理解和掌握 Vue.js 的核心概念和技术。订

    2024年01月21日
    浏览(71)
  • VUE--组件通信(非父子)

    一、非父子通信  ---  event bus 事件总线         作用:非父子组件之间进行 简易的消息传递         步骤:                    1、创建一个都能访问到的事件总线(空vue实例)--- utils/EventBus.js                   2、 接收方(A组件),监听Bus实例的事件        

    2024年01月19日
    浏览(65)
  • 前端基础(props emit slot 父子组件间通信)

    前言 :如何实现组件的灵活使用,今天学习组件封装用到的props、slot和emit。 目录 props 子组件 父组件 示例代码 slot 示例代码 作用域插槽 emit 示例代码 需要实现在其他组件中使用同一个子组件。 子组件(所谓子组件,就是封装好的组件,供其他组件使用) 子组件定义了so

    2024年02月11日
    浏览(52)
  • 【vue3】vue3中父子组件传参:

    一、父传子: 【1】父组件传值: 【2】子组件接收: 二、父调用子方法: 【1】父组件调用: 【2】子组件暴露: 三、子组件发送emit方法给父组件: 【1】父组件: 【2】子组件调用:

    2024年02月13日
    浏览(41)
  • VUE 父子组件、兄弟组件 之间通信 最强详解

    目录 1. 父组件 调用 子组件 内参数/方法 1.1 通过 ref 调用/获取 子组件内参数/方法 2. 子组件 调用 父组件 内参数/方法 2.1 通过 emit 调用 父组件方法 2.2 通过 props 调用 父组件方法/参数 2.3 通过 this.$parent 调用 父组件方法/参数 3. 兄弟组件 通信 3.1 通过 bus 进行 兄弟组件 通信

    2024年02月05日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包