Vue3父子组件传属性和方法调用Demo

news2024/9/22 13:40:45

Vue3父子组件传属性和方法调用Demo

  • 说明
  • 目录
  • 父组件给子组件传值和方法
    • 父组件给子组件传值-使用defineProps接受父组件属性值
    • 父组件给子组件传值-使用defineModel接受父组件v-model值
      • 当子组件只需要接收父组件一个v-model值时,写法1如下:
      • 子组件接收单个v-model写法2如下:
      • 当子组件需要接收父组件多个v-model值时,写法如下:
    • 父组件给子组件传方法
  • 子组件调用父组件方法-使用defineEmits调用父组件方法
  • 子组件暴露属性和方法给父组件调用-使用defineExpose暴露子组件属性和方法

说明

这里记录下自己学习Vue3父子组件怎么传值和方法怎么互相调用,防止后面继续踩坑且方便以后直接使用。这里承接自己的博客Vue3+vite优化基础架构(3)— 优化vue-i18n国际化配置这篇博客,在该博客项目的基础上学习Vue3父子组件传值及使用。

官方文档:https://cn.vuejs.org/api/sfc-script-setup.html#defineprops-defineemits

目录

在这里插入图片描述
这里父组件是test-management1文件夹下的index.vue,子组件是test-management1文件夹下的components文件夹的test-child.vue。

父组件给子组件传值和方法

父组件给子组件传属性值,有2种方式:

  1. 第一种方式是在子组件里面使用defineProps来接受父组件那边传过来的属性值。
  2. 第二种方式是在子组件里面使用defineModel来接受父组件那边传过来的v-model值。

父组件给子组件传值-使用defineProps接受父组件属性值

父组件代码如下:

<template>
  <div>测试管理1页面</div>
  <div>
    <!--在父组件里面使用子组件TestChild-->
    <!--父组件向子组件传参,参数为name,age,isOpenEmail,content,score这5-->
    <TestChild
        :name="testName"
        :age="testAge"
        :isOpenEmail="testIsOpenEmail"
        :content="testContent"
        :score="testScore"
    />
  </div>
</template>

<script setup name="test-management1">
  import {ref} from "vue"
  //引入子组件
  import TestChild from './components/test-child.vue'

  //定义name值
  const testName=ref('张三')
  //定义age值
  const testAge=ref(18)
  //定义isOpenEmail开通邮箱值
  const testIsOpenEmail=ref(false)
  //定义content值
  const testContent=ref(['测试值1','测试值2','测试值3'])
  //定义score值
  const testScore=ref({
    curriculum:"语文",
    score:60
  })
</script>

<style scoped>

</style>

子组件代码如下:

<template>
  <!--显示父组件传过来的参数值-->
  <div>
    <!--在页面模版里面如果要使用父组件里面穿过来的参数,有2种写法,都能在页面显示出来:-->
    <!--第一种全写:{{props.name}}-->
    <div>name名字为:{{props.name}}</div>
    <!--第二种简写:{{name}},这种简写有个问题,如果你在js中定义了一个相同名的参数,它会优先读取定义的那个参数,不会去读父组件传过来的参数-->
    <div>name名字为:{{name}}</div>
    <div>age年龄为:{{props.age}}</div>
    <div>isOpenEmail是否开通邮箱为:{{props.isOpenEmail}}</div>
    <div>content内容为:{{props.content[0]}}</div>
    <div>score分数为:{{props.score.score}}</div>
  </div>
</template>

<script setup>
  import {onMounted} from 'vue'

  //const name="haha"

  //页面初始化时执行
  onMounted(() => {
    console.info("从父组件那边传过来的值为:")
    console.info("name:",props.name)
    console.info("age:",props.age)
    console.info("isOpenEmail:",props.isOpenEmail)
    console.info("content:",props.content)
    console.info("score:",props.score)
  })

  //使用defineProps接收父组件穿传过来的参数
  const props = defineProps({
    //从父组件那边接收一个String类型的参数,参数名叫name(名字)
    name: {
      required:false,//是否必须传该name参数,不写默认为false,true为必须传该参数,false为可以不传该name参数
      type: String,//参数类型为String字符串
      default: ''//默认值为空值
    },
    //从父组件那边接收一个Number类型的参数,参数名叫age(年龄)
    age: {
      type: Number,//参数类型为Number整型
      default: 0//默认值为0
    },
    //从父组件那边接收一个Boolean类型的参数,参数名叫isOpenEmail(是否开通邮箱)
    isOpenEmail: {
      type: Boolean,//参数类型为Boolean布尔类型
      default: false//默认值为false
    },
    //从父组件那边接收一个content类型的参数,参数名叫content(内容)
    content: {
      type: Array,//参数类型为Array数组类型
      default: []//默认值为空数组
    },
    //从父组件那边接收一个Object类型的参数,参数名叫score(分数)
    score: {
      type: Object,//参数类型为Object对象类型
      default: {}//默认值为空对象
    }
  })
</script>

<style scoped>

</style>

谷歌浏览器效果显示
在这里插入图片描述
注意事项
1.在页面模版中如果直接使用简写{{name}}这种写法,如果在js中又重新定义了一个name属性,那么会优先使用定义的这个name值,不会使用父组件那边传值过来的name属性值。如下:
在这里插入图片描述
在这里插入图片描述

2.如果子组件接收的参数有required属性而且为true,如果父组件不传该属性的话,那么控制台会出现警告。如下:
在这里插入图片描述
在这里插入图片描述
浏览器结果如下:
在这里插入图片描述

父组件给子组件传值-使用defineModel接受父组件v-model值

当子组件只需要接收父组件一个v-model值时,写法1如下:

父组件代码:

<template>
  <div>测试管理1页面</div>
  <div>
    <!--在父组件里面使用子组件TestChild-->
    <!--父组件向子组件传参,使用v-model形式进行双向绑定-->
    <TestChild
        v-model="testName"
    />
  </div>
</template>

<script setup name="test-management1">
  import {ref} from "vue"
  //引入子组件
  import TestChild from './components/test-child.vue'

  //定义name值
  const testName=ref('张三')

</script>

<style scoped>

</style>

子组件代码:

<template>
  <!--显示父组件传过来的参数值-->
  <div>
    <el-input v-model="modelValue"></el-input>
  </div>
</template>

<script setup>
  import {onMounted} from 'vue'

  //页面初始化时执行
  onMounted(() => {

  })

  //直接使用解构写法来接收父组件那边通过v-model传过来的值,必须使用modelValue来接收属性值
  const [modelValue]=defineModel()
  console.info("子组件接收父组件的name值为:",modelValue.value)
</script>

<style scoped>

</style>

谷歌浏览器结果如下:
在这里插入图片描述

子组件接收单个v-model写法2如下:

<template>
  <!--显示父组件传过来的参数值-->
  <div>
    <el-input v-model="name"></el-input>
  </div>
</template>

<script setup>
  import {onMounted} from 'vue'

  //页面初始化时执行
  onMounted(() => {
    console.info("子组件接收父组件的v-model值为:",name.value)
  })

  //直接使用defineModel接受父组件通过v-model传过来的值
  //子组件这边定义一个name属性来接收父组件那边传过来的v-model的值,简写形式如下
  const name=defineModel()
  //完整写法
  /*const name = defineModel({
    type: String,//字段类型
    default: ''//默认空值
  })*/
  //等同于上面的default: ''写法
  /*const name = defineModel({
    type: String,//字段类型
    default: () => {//扩展:将默认属性作为一个方法使用,可以执行一段自定义逻辑,这里直接返回了一个空值,等同于上面写法
      return ''
    }
  })*/

</script>

<style scoped>

</style>

浏览器结果如下:
在这里插入图片描述

当子组件需要接收父组件多个v-model值时,写法如下:

父组件代码:

<template>
  <div>测试管理1页面</div>
  <div>
    <!--在父组件里面使用子组件TestChild-->
    <!--父组件向子组件传参,使用v-model形式进行双向绑定-->
    <!--绑定多个v-model时,v-model冒号后面为参数名称,后面为参数值-->
    <!--向子组件传参属性为testName,testAge,testIsOpenEmail,testContent,testScore这5个参数-->
    <TestChild
        v-model:testName="name"
        v-model:testAge="age"
        v-model:testIsOpenEmail="isOpenEmail"
        v-model:testContent="content"
        v-model:testScore="score"
    />
  </div>
</template>

<script setup name="test-management1">
  import {ref} from "vue"
  //引入子组件
  import TestChild from './components/test-child.vue'

  //定义name值
  const name=ref('张三')
  //定义age值
  const age=ref(18)
  //定义isOpenEmail开通邮箱值
  const isOpenEmail=ref(false)
  //定义content值
  const content=ref(['测试值1','测试值2','测试值3'])
  //定义score值
  const score=ref({
    curriculum:"语文",
    score:60
  })

</script>

<style scoped>

</style>

子组件代码:

<template>
  <!--显示父组件传过来的参数值-->
  <div>
  	<!--使用父组件那边传过来的name值-->
    <el-input v-model="name"></el-input>
  </div>
</template>

<script setup>
  import {onMounted} from 'vue'

  //页面初始化时执行
  onMounted(() => {
    console.info("子组件接收父组件的v-model值为:")
    console.info("name:",name.value)
    console.info("age:",age.value)
    console.info("isOpenEmail:",isOpenEmail.value)
    console.info("content:",content.value)
    console.info("score:",score.value)
  })

  //直接使用defineModel接受父组件通过v-model传过来的值
  //子组件这边自定义一个name属性来接收父组件那边传过来的v-model(testName)的值,简写形式如下
  const name=defineModel('testName')
  //完整写法
  /*const name = defineModel('testName',{
    type: String,//字符串类型
    default: ''//默认值为空
  })*/
  //子组件这边自定义一个age属性来接收父组件那边传过来的v-model(testAge)的值
  const age = defineModel('testAge',{
    type: Number,//整型类型
    default: 0//默认值为0
  })
  //子组件这边自定义一个isOpenEmail属性来接收父组件那边传过来的v-model(testIsOpenEmail)的值
  const isOpenEmail = defineModel('testIsOpenEmail',{
    type: Boolean,//布尔类型
    default: false//默认值为false
  })
  //子组件这边自定义一个content属性来接收父组件那边传过来的v-model(testContent)的值
  const content = defineModel('testContent',{
    type: Array,//数组类型
    default: []//默认值为空数组
  })
  //子组件这边自定义一个score属性来接收父组件那边传过来的v-model(testScore)的值
  const score = defineModel('testScore',{
    type: Object,//对象类型
    default: {}//默认值为空对象
  })
</script>

<style scoped>

</style>

浏览器结果如下:
在这里插入图片描述

父组件给子组件传方法

父组件代码:

<template>
  <div>测试管理1页面</div>
  <div>
    <!--在父组件里面使用子组件TestChild-->
    <!--父组件向子组件传递一个方法,方法名为print-->
    <TestChild
        :print="testPrint"
    />
  </div>
</template>

<script setup name="test-management1">
  import {ref} from "vue"
  //引入子组件
  import TestChild from './components/test-child.vue'

  //定义print方法
  const testPrint = () => {
    console.info("我是父组件的testPrint方法。")
  }
</script>

<style scoped>

</style>

子组件代码:

<template>
  <!--显示父组件传过来的参数值-->
  <div>
    子组件
  </div>
</template>

<script setup>
  import {onMounted} from 'vue'

  //页面初始化时执行
  onMounted(() => {
    //调用父组件那边传过来的方法
    props.print()
  })

  //使用defineProps接受父组件穿传过来的参数
  const props = defineProps({
    //从父组件那边接收一个方法,参数名叫print
    print: {
      type: Function,//参数类型为Function方法类型
      default: () =>{}//默认一个空方法
    }
  })


</script>

<style scoped>

</style>

谷歌浏览器结果如下:
在这里插入图片描述

子组件调用父组件方法-使用defineEmits调用父组件方法

父组件代码:

<template>
  <div>测试管理1页面</div>
  <div>
    <!--在父组件里面使用子组件TestChild-->
    <!--自定义一个testChange方法-->
    <TestChild
        @testChange="change"
    />
  </div>
</template>

<script setup name="test-management1">
  import {ref} from "vue"
  //引入子组件
  import TestChild from './components/test-child.vue'

  //父组件定义一个change方法
  const change = (val) => {
    console.info("我是父组件的change方法,参数值为:",val)
  }

</script>

<style scoped>

</style>

子组件代码:

<template>
  <!--子组件-->
  <div>
    我是子组件
    <!--不使用js的话,模版页面直接调用父方法并传递参数写法如下:-->
<!--    <el-button @click="$emit('testChange','2222')"></el-button>-->
  </div>
</template>

<script setup>
  //使用defineEmits接收父组件自定义的testChange方法
  const emit=defineEmits(['testChange'])
  //子组件调用父组件中的testChange方法,并给该方法传递了一个参数值为2222
  emit('testChange', '2222')
</script>

<style scoped>

</style>

浏览器结果如下:
在这里插入图片描述

子组件暴露属性和方法给父组件调用-使用defineExpose暴露子组件属性和方法

子组件代码:

<template>
  <!--子组件-->
  <div>
    <div>name名字为:{{name}}</div>
    <div>age年龄为:{{age}}</div>
    <div>isOpenEmail是否开通邮箱为:{{isOpenEmail}}</div>
    <div>content内容为:{{content}}</div>
    <div>score分数为:{{score}}</div>
  </div>
</template>

<script setup>
  import {ref} from "vue"

  //定义name值
  const name=ref('张三')
  //定义age值
  const age=ref(18)
  //定义isOpenEmail开通邮箱值
  const isOpenEmail=ref(false)
  //定义content值
  const content=ref(['测试值1','测试值2','测试值3'])
  //定义score值
  const score=ref({
    curriculum:"语文",
    score:60
  })
  //测试方法
  const test = (val) => {
    console.info("我是子组件的test方法,参数值是=",val)
  }
  //使用defineExpose暴露属性和方法,暴露了name,age,isOpenEmail,content,score这5个属性值和1个test方法给父组件调用
  defineExpose({
    name,
    age,
    isOpenEmail,
    content,
    score,
    test
  })
</script>

<style scoped>

</style>

父组件代码:

<template>
  <div>测试管理1页面</div>
  <div>
    <!--在父组件里面使用子组件TestChild-->
    <!--如果子组件里面暴露了属性和方法,子组件必须要加ref才能在父组件中调用子组件里面的属性和方法-->
    <TestChild ref="testChildRef"/>
  </div>
</template>

<script setup name="test-management1">
  import {ref,onMounted} from "vue"
  //引入子组件
  import TestChild from './components/test-child.vue'

  //页面初始化加载
  onMounted(() => {
    //调用子组件里面的暴露的属性和方法,要用ref去调用
    console.info("父组件中调用子组件中属性值:")
    console.info("name值:",testChildRef.value.name)
    console.info("age值:",testChildRef.value.age)
    console.info("isOpenEmail值:",testChildRef.value.isOpenEmail)
    console.info("content值:",testChildRef.value.content)
    console.info("score值:",testChildRef.value.score)
    console.info("父组件中调用子组件中方法:")
    testChildRef.value.test('111')
  })

  //子组件ref名称
  const testChildRef=ref()

</script>

<style scoped>

</style>

浏览器结果如下:
在这里插入图片描述
注意事项
如果父组件中调用了子组件未暴露的属性或者方法或者不存在的属性和方法,那么浏览器控制台会报错,如下:
在这里插入图片描述
在这里插入图片描述
父子组件的传值和方法互相调用就学习到这里了,后面要是遇到新的方式在扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1967032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计界的新宠:5款热门UI在线设计软件评测

随着用户界面设计行业的蓬勃发展&#xff0c;越来越多的设计师进入用户界面设计。选择一个方便的用户界面设计工具尤为重要&#xff01;除了传统的用户界面设计工具&#xff0c;在线用户界面设计工具也受到越来越多设计师的青睐。这种不受时间、地点、计算机配置限制的工作方法…

12. 计算机网络TCP四次挥手

1. 前言 上一章节分析了 TCP 建立连接的过程,既然有建立连接,对应的也有断开连接。数据传输完成之后,客户端和服务器端保持通信状态会占用资源开销,所以需要断开连接,TCP 协议中断开连接也被称为 TCP 四次挥手。 2.1 TCP 四次挥手 面试官提问: 说明一下 TCP 断开连接的…

Azure AD 配置角色,在Blazor中从Claims读取角色

首先是在 Microsoft Entra admin center 中配置你的应用程序角色 然后分配用户到你创建的角色 1. 首先从下图找到你要配置的程序 2. 然后找到分配用户到角色的地方 选择用户 再选择角色 这样就成功给用户分配了权限 接下来就可以在Blazor页面中读取了 using Microsoft.AspNe…

安居客全国小区(名称、价格、地区、地址)数据快速整理导出

安居客二手房小区全国(南京|重庆|青岛|天津|杭州|成都|沈阳|武汉|长沙|西安)实时数据&#xff0c;含小区名称、价格、地区、地址、商圈、标签、经纬度、物业类型、交易权属、竣工时间、产权年限、开发商、总户数、总建面积、绿化率、容积率、统一供暖 供水供电、停车位、停车费…

ruoyi若依框架中货道关联商品

<el-button link type"primary" click"handleGoods(scope.row)" v-hasPermi"[manage:vm:edit]">货道</el-button> <!-- 货道组件 --> <ChannelDialog :goodVisible"goodVisible" :goodData"goodData" …

职业本科综合布线实训室

一、职业本科综合布线实训室建设背景 在数字化时代的大潮中&#xff0c;网络技术作为推动社会进步的重要力量&#xff0c;其地位日益凸显。随着云计算、大数据、物联网、人工智能等技术的不断发展和融合&#xff0c;网络技术的边界和应用领域不断扩展&#xff0c;对于掌握现代…

无线领夹麦克风怎么选,直播唱歌只用领夹麦可以吗?

现如今视频自媒体行业还在蓬勃发展&#xff0c;麦克风对于自媒体行业可以说是必不可少的装备了&#xff0c;在互联网“内卷”的时代&#xff0c;各大视频博主、Up主、主播大多都会使用无线麦克风来辅助视频和直播内容输出。无线领夹麦克风作为视频行业中的麦克风新宠&#xff0…

script 加载的三种方式详解

首屏优化这个问题想必已经老生常谈了&#xff0c;在面试当中也是经常被提及到&#xff0c;例如&#xff0c;面试官&#xff1a;有没有做过首屏优化&#xff0c;首屏优化都有哪些方案&#xff1f;当然在首屏优化中并没有一套方案是一劳永逸的&#xff0c;要根据具体网站首页的需…

【vluhub】weblogin之xxe实体注入

XXE 漏洞 XXE漏洞&#xff0c;全称XML外部实体注入漏洞&#xff0c;是一种常见的针对解析XML输入的应用程序的安全漏洞。当应用程序在解析XML数据时&#xff0c;如果没有正确验证或限制实体引用&#xff0c;攻击者就可以通过构造恶意的XML输入&#xff0c;将外部实体引用进来&…

NLB快速实现IPv4服务的负载均衡

阿里云网络型负载均衡NLB&#xff08;Network Load Balancer&#xff09;支持TCP、UDP和TCPSSL协议&#xff0c;提供了强大的四层负载均衡能力。 为了实现IPv4服务的负载均衡&#xff0c;需要快速创建一个NLB实例&#xff0c;并将来自客户端的访问请求转发至后端服务器。 操作…

自闭症儿童能否摘帽?摘帽成功的秘诀揭秘

自闭症&#xff0c;这一曾经被视为不可逆转的障碍&#xff0c;如今在科学的进步与社会的关注下&#xff0c;正逐步展现出被“摘帽”的可能性。那么&#xff0c;自闭症儿童真的能完全摆脱这一标签&#xff0c;实现真正的“摘帽”吗&#xff1f;答案是肯定的&#xff0c;关键在于…

开发效率提升利器:5款支持C#语言的AI辅助编程工具

前言 在这个AI迅速发展的阶段&#xff0c;涌现出了一大批好用的AI辅助编程工具。AI辅助编程工具能够提高开发效率、改善代码质量、降低bug率&#xff0c;是现代软件开发过程中的重要助手。今天大姚给大家分享5款AI辅助编程工具&#xff08;并且都支持C#语言&#xff09;&#…

大屏自适应方案

1.npm下载 npm i autofit.js2.在项目中引入 import autofit from autofit.js3.init(&#xff09;初始化&#xff0c;注意&#xff1a;要在mounted&#xff08;&#xff09;里

0.01 /小时,使用超算互联网https://www.scnet.cn/国产卡推理微调大模型,初体验

0.01 /小时&#xff0c;使用超算互联网 https://www.scnet.cn/ 国产卡推理微调大模型&#xff0c;初体验 官网购买算力,国产卡活动0.01 /小时&#xff0c;非常划算 活动地址 https://www.scnet.cn/home/subject/modular/index264.html 扫码入群&#xff0c;每天领算力优惠券&…

服务器集群中 IP 地址管理混乱

服务器集群为各种关键业务提供强大的计算和存储能力。但如果服务器集群的 IP 地址管理混乱会给服务的部署和维护带来影响。 服务器集群与 IP 地址的关系 服务器集群是由一组相互连接的服务器组成&#xff0c;共同工作以提供更高的性能、可用性和可扩展性。IP 地址则是服务器在…

软件测试面试101问(附答案)

前言 前阵子一位读者告诉我&#xff0c;某位大厂HR给他发了我之前做的面试题答案合集。 这个消息让我开心了一整天&#xff0c;因为这说明我之前做的面试题系列真的能帮助到部分测试同学&#xff0c;也算是侧面得到了一种认可吧。 今天写的这份面试题我之前就整理分享过&…

结合LangChain实现网页数据爬取

LangChain 非常强大的一点就是封装了非常多强大的工具可以直接使用。降低了使用者的学习成本。比如数据网页爬取。 在其官方文档-网页爬取中&#xff0c;也有非常好的示例。 应用场景 信息爬取。 RAG 信息检索。 实践应用 需求说明 从 ceshiren 网站中获取每个帖子的名称…

Grafana Loki 架构组件详解

在本指南中&#xff0c;我们将详细了解Grafana Loki架构及其组件。 在公司的分布式环境中&#xff0c;存储和管理来自各种系统资源的日志是一项具有挑战性的任务。为了简化这项任务&#xff0c;引入了一个称为日志聚合的概念&#xff0c;它从各种系统资源中收集、存储、管理日…

(3)基于巴法云+MQTT+微信小程序控制esp8266点灯

1、配置微信公众平台 在 微信公众平台 注册 小程序 账号&#xff0c;拿到小程序 appid&#xff0c;登录到微信公众平台后在 开发者ID 里面可以看到&#xff0c;长的大概是这样&#xff1a;wx34a2063de5yyc04b&#xff0c;下面导入项目的时候会用到。 然后在 服务器域名 的后面…